emberjs/ember.js · error · Error
Cannot update a frozen TrackedValue${this.#options.descripti
Error message
Cannot update a frozen TrackedValue${this.#options.description ? ` (\`${this.#options.description}\`)` : ''} What it means
A TrackedValue can be frozen (via freeze() / createStorage freeze semantics) after which its `set` method refuses updates, because notifying consumers of a change on a frozen value is undefined behavior. If a description was provided when creating the value it is included in the message to identify the culprit.
Source
Thrown at packages/@glimmer/validator/lib/tracked-value.ts:69
this.set(value);
}
/**
* Function short-hand for reading `value`.
*/
get = (): Value => {
return this.value;
};
/**
* Function short-hand for assigning `value`.
*
* Returns `true` if the value changed (and consumers were notified),
* `false` if the new value was equal to the current one.
*/
set = (value: Value): boolean => {
if (this.#isFrozen) {
throw new Error(
`Cannot update a frozen TrackedValue${
this.#options.description ? ` (\`${this.#options.description}\`)` : ''
}`
);
}
if (this.#options.equals(this.#value, value)) {
return false;
}
this.#value = value;
DIRTY_TAG(this.#tag);
return true;
};
/**View on GitHub (pinned to 26f97246a8)
Solutions
- Stop writing to that value after it is frozen — restructure so mutations happen before freezing.
- Create a new TrackedValue (or cell) instead of updating the frozen one, and update consumers' references to it.
- Check which code path calls freeze() on it (search the description string in the error) and remove the freeze if updates are intended.
Example fix
// before
let cell = createStorage('my value', description('cell'));
cell.value = 'a';
freeze(cell);
cell.value = 'b'; // throws
// after
let cell = createStorage('my value', description('cell'));
cell.value = 'a';
freeze(cell);
if (needsUpdate) {
cell = createStorage('b', description('cell'));
} Defensive patterns
Strategy: type-guard
Validate before calling
function canSet(cell) {
return !cell.isFrozen; // expose/track freeze state if wrapping storage
}
if (canSet(myCell)) myCell.value = next; Type guard
function isWritableCell(cell) {
return cell != null && typeof cell.set === 'function' && cell.isFrozen !== true;
} Try / catch
try {
cell.set(next);
} catch (e) {
if (String(e.message).startsWith('Cannot update a frozen TrackedValue')) {
// replace the frozen value with a new TrackedValue instead
} else throw e;
} Prevention
- Treat frozen TrackedValues as immutable snapshots; allocate a new one for updates.
- Perform all mutations before calling freeze().
- Give every TrackedValue a description so error messages identify it instantly.
- Audit `cached` getters: never write to tracked storage read during caching.
When it happens
Trigger: Calling `set(value)` on a TrackedCell/TrackedValue after `freeze()` was called on it, e.g. mutating a cached cell after its containing snapshot was frozen, or writing to a const-tracked storage in a DEBUG check.
Common situations: Trying to update a value captured inside a `cached` getter's frozen epoch; writing to storage created by a library that froze it intentionally; holding a stale reference to a cell that was frozen when a component finalized.
Related errors
- attempted to close a tracking frame, but one was not open
- The `@glimmer/validator` library has been included twice in
- Compile Error: ${template.problem} @ ${template.span.start}.
- A resolved helper cannot be passed as a named argument as th
- deprecation override for ${id} not found
AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01).
Data as JSON: /api/errors/7fab32c57be815e9.
Report an issue: GitHub.