## TL;DR

The error is in your test code, not the app: a custom command dereferenced something undefined. Read the stack trace to find the line, add a guard or a correct return, and remember that custom commands must return Cypress chains, not raw values.

## Error

```text
TypeError: Cannot read properties of undefined (reading 'id')
    at Context.eval (cypress/support/commands.js:42:19)
```

## Steps

1. Open the stack trace; the frame inside `cypress/support/commands.js` (or your support file) is your code. Expected: a line number pointing at the dereference.
2. Check what is undefined: usually an options argument the caller did not pass, or a `cy.get()` result used outside a `.then()`. Expected: you find the missing value.
3. Fix by defaulting the argument (`options = {}`) or by moving the logic inside `.then()`. Expected: the command handles the absent value explicitly.
4. Make sure the custom command returns the chain: `Cypress.Commands.add('login', () => { return cy.get(...).type(...) })`. Expected: callers can chain off `cy.login()`.
5. Re-run the spec that uses the command. Expected: green, and other specs using the same command still pass.

## When to use

- Stack trace points into `cypress/support/` or your spec files.
- The error is a TypeError, not a CypressError.

## When not to use

- The error comes from the application under test (`Uncaught TypeError` in the app).
- The failure is a Cypress assertion timeout.

## Tool compatibility

- Cypress 10 through 14; custom commands in `cypress/support/commands.js`.

## Variant phrasings

### Cannot read properties of null (reading '...')

Same class of bug with null instead of undefined; same fix.

### cy.task() returned undefined

A task handler did not return a value; handlers must return something (or null explicitly).

## Why it happens

Custom commands run in Node-side spec code. Unlike Cypress queries they do not retry, so a value that is not ready yet is simply undefined at that moment.

## Edge cases

- Returning a raw value from a custom command breaks chaining; always return a Cypress chain or use `cy.wrap()`.
- `Cypress.Commands.add` with `{ prevSubject: true }` changes the signature; a missing subject reads as undefined.
- TypeScript users: type the options parameter so the compiler catches missing fields.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_nn7r5fYapwpv9AHEjnOrsQ
