---
title: "Cannot read properties of undefined, in a wire handler"
url: "https://trailassembly.com/lwc-cannot-read-properties-undefined/"
topic: "LWC and Front-End"
published: "2026-09-12T10:09:37+00:00"
updated: "2026-10-06T13:53:40+00:00"
---

# Cannot read properties of undefined, in a wire handler

**The short answer:** your wire adapter emits before the data arrives, so the property you are reading is `undefined` at the moment the getter or the template runs. The error is not telling you the record is missing. It is telling you that you wrote code that assumed a wire has two states when it has three.

## The error and where it comes from

You will see something like this in the browser console, usually several times on one page load:

```apex
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'fields')
```

The clue is the property name in brackets. `reading 'fields'` means something evaluated `somethingUndefined.fields`. `reading 'data'` means the wired property itself did not exist yet. Read that name first, then go looking for the expression that contains it.

## A wire has three states, not two

People write the handler as if `data` or `error` is always populated. Neither is, at first:

1. **Pending.** `data` and `error` are both `undefined`. The component has already rendered.

2. **Loaded.** `data` is set, `error` is `undefined`.

3. **Failed.** `error` is set, `data` is `undefined`.

The order matters. Your `connectedCallback` runs, your template renders, and only then does the wire resolve. Every getter referenced in that first render executes against the pending state. So this crashes on the very first render, every single time:

```apex
@wire(getRecord, { recordId: '$recordId', fields: FIELDS })
account;

get ownerName() {
    return this.account.data.fields.Owner.displayValue;  // boom
}
```

There is a fourth state people forget: a [reactive](https://trailassembly.com/flow-reactive-screen-components/) parameter that has not been set yet. If `recordId` arrives from the page as a property, the wire fires once with `$recordId` undefined, gets nothing useful back, and fires again when the value lands.

## Fix one: optional chaining, and where it is not enough

Optional chaining short-circuits the whole expression the moment anything in the chain is null or undefined.

```apex
get ownerName() {
    return this.account?.data?.fields?.Owner?.displayValue ?? '';
}
```

The `??` at the end matters as much as the `?.` in the middle. Without it the getter returns `undefined`, the template renders an empty string anyway, and a downstream `.toUpperCase()` throws the same error one line later.

For record data, stop writing that chain entirely. `getFieldValue` from `lightning/uiRecordApi` handles undefined input and spanning fields:

```apex
import { getFieldValue } from 'lightning/uiRecordApi';
import OWNER_NAME from '@salesforce/schema/Account.Owner.Name';

get ownerName() {
    return getFieldValue(this.account.data, OWNER_NAME);
}
```

Optional chaining does not help with arrays. `this.contacts?.data` being undefined is safe, but `this.contacts.data[0].Name` still throws on an empty result set, because an empty array is perfectly defined and has no index zero. Check `length`.

## Fix two: guard the template, do not patch the getters

Cleaner than sprinkling `?.` everywhere: render nothing until there is something to render.

```apex
<template lwc:if={account.data}>
    <p>{ownerName}</p>
</template>
<template lwc:elseif={account.error}>
    <p class="slds-text-color_error">Could not load the account.</p>
</template>
<template lwc:else>
    <lightning-spinner alternative-text="Loading"></lightning-spinner>
</template>
```

This is better than the optional-chaining approach because it handles all three states visibly. A user gets a spinner, then either the data or an error. The version that guards only the getters shows a blank panel for both loading and failure, and your support team cannot tell them apart.

## The wired-function variant

If you wire a function rather than a property, you are handed the states explicitly and you must handle the empty one yourself:

```apex
@wire(getRecord, { recordId: '$recordId', fields: FIELDS })
wiredAccount({ data, error }) {
    if (data) {
        this.name = getFieldValue(data, NAME);
    } else if (error) {
        this.errorMessage = reduceErrors(error).join(', ');
    }
    // the pending call falls through both branches, which is correct
}
```

Assigning `this.name = data.fields.Name.value` without the `if (data)` is the same bug in a different shape. The function runs on the pending emission too.

## When it is not the wire at all

Two other sources produce the identical message. Reading `this.template.querySelector(...)` in `connectedCallback` returns null, because the template has not rendered yet. Move that to `renderedCallback`. And an Apex method that returns null for a filtered query gives you a defined wired property with `data` set to `null`, which passes a truthiness check on the property and fails on the next dot.

## Frequently asked

**Why does it appear three times per page load?** Once per render pass. The initial render, the render after the reactive parameter resolves, and the render after the data arrives.

**Should I initialise the property to an empty object?** No. That hides the pending state and gives you a component that renders as loaded with nothing in it.

**Does this happen with imperative Apex too?** Yes, between the call and the resolved promise. The same guard applies, and the template usually needs the same three branches.

---

Source: https://trailassembly.com/lwc-cannot-read-properties-undefined/
Trail Assembly — independent Salesforce write-ups.
