facebook/react · error · Error

Expected counter to be known.

Error message

Expected counter to be known.

What it means

removeRootPseudoKey parses the root's pseudo key back into name and counter, then requires rootDisplayNameCounter to still have an entry for that name. The throw means the name/counter bookkeeping diverged - the counter map no longer matches the pseudo keys handed out earlier (e.g. re-mounts incremented counters without matching decrements, or the maps were rebuilt by a filter re-mount while a stale key remained).

Source

Thrown at packages/react-devtools-shared/src/backend/fiber/renderer.js:7797

  const rootDisplayNameCounter: Map<string, number> = new Map();

  function setRootPseudoKey(id: number, fiber: Fiber) {
    const name = getDisplayNameForRoot(fiber);
    const counter = rootDisplayNameCounter.get(name) || 0;
    rootDisplayNameCounter.set(name, counter + 1);
    const pseudoKey = `${name}:${counter}`;
    rootPseudoKeys.set(id, pseudoKey);
  }

  function removeRootPseudoKey(id: number) {
    const pseudoKey = rootPseudoKeys.get(id);
    if (pseudoKey === undefined) {
      throw new Error('Expected root pseudo key to be known.');
    }
    const name = pseudoKey.slice(0, pseudoKey.lastIndexOf(':'));
    const counter = rootDisplayNameCounter.get(name);
    if (counter === undefined) {
      throw new Error('Expected counter to be known.');
    }
    if (counter > 1) {
      rootDisplayNameCounter.set(name, counter - 1);
    } else {
      rootDisplayNameCounter.delete(name);
    }
    rootPseudoKeys.delete(id);
  }

  function getDisplayNameForRoot(fiber: Fiber): string {
    let preferredDisplayName = null;
    let fallbackDisplayName = null;
    let child = fiber.child;
    // Go at most three levels deep into direct children
    // while searching for a child that has a displayName.
    for (let i = 0; i < 3; i++) {
      if (child === null) {
        break;

View on GitHub (pinned to eafeac097b)

Solutions

  1. Reload the page with DevTools open - counters are rebuilt consistently on a fresh session.
  2. Reduce concurrent filter toggling while roots mount/unmount.
  3. Upgrade DevTools/React to pick up counter bookkeeping fixes.
  4. Report with the sequence of filter toggles + root unmounts if it persists.
Defensive patterns

Strategy: fallback

Try / catch

// when embedding devtools-shared: counter map diverged from pseudo keys - reset session
try {
  renderer.handleCommitFiberRoot(root, priorityLevel);
} catch (err) {
  if (err.message.includes('Expected counter to be known')) {
    location.reload(); // counters are session-local and rebuilt on fresh attach
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Unmounting a root whose display-name counter entry is gone - typically after repeated filter re-mounts rewrote rootPseudoKeys/rootDisplayNameCounter while an old key survived, or duplicate teardown of the same display name.

Common situations: Repeatedly toggling component filters in multi-root apps (several roots with the same display name); fast refresh remount storms; long DevTools sessions across many root create/destroy cycles.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/c8aeb2d834495187. Report an issue: GitHub.