Not verified hands-on. This article was written from primary documentation rather than reproduced in an org, so it carries no tested-release badge. If you run it and something differs, say so in the comments and it gets tested and corrected.

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:

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:

@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 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.

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:

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.

<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:

@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.