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

  1. Stop writing to that value after it is frozen — restructure so mutations happen before freezing.
  2. Create a new TrackedValue (or cell) instead of updating the frozen one, and update consumers' references to it.
  3. 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

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


AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01). Data as JSON: /api/errors/7fab32c57be815e9. Report an issue: GitHub.