stablyai/orca · error · Error

post-mutation hooks/list reported ${byNewKey.size} of ${requ

Error message

post-mutation hooks/list reported ${byNewKey.size} of ${request.moves.length} moved user hooks

What it means

Thrown by repairUserHookTrust when the post-mutation hooks/list call did not return all expected user hooks matched by their newKey (and matching command). After hooks.json was mutated to relocate hooks, codex's hooks/list should report each hook under its new key; a shortfall means the mutation didn't land as expected and rebasing trust now would be inconsistent.

Source

Thrown at src/main/codex/codex-user-hook-trust-rebase-client.ts:137

        return {
          ...move,
          reportedOldKey: listing.key,
          wasTrusted: listing.trustStatus === 'trusted',
          enabled: listing.enabled
        }
      })
    }
  })
}

async function repairUserHookTrust(
  request: CodexUserHookTrustRepairRequest
): Promise<CodexUserHookTrustRebaseResult> {
  return runCodexAppServerSession(request.invocation, async ({ request: requestRpc }) => {
    const result = await requestRpc('hooks/list', { cwds: [request.hooksListCwd] })
    const byNewKey = matchingListings(collectCodexHookListings(result), request.moves, 'newKey')
    if (byNewKey.size !== request.moves.length) {
      throw new Error(
        `post-mutation hooks/list reported ${byNewKey.size} of ${request.moves.length} moved user hooks`
      )
    }

    const keysToClear = new Set([
      ...request.moves.map((move) => move.reportedOldKey),
      ...Array.from(byNewKey.values(), (listing) => listing.key)
    ])
    const edits: { keyPath: string; value: unknown; mergeStrategy: 'replace' }[] = Array.from(
      keysToClear,
      (key) => ({
        keyPath: quotedKeyPath(key),
        value: null,
        mergeStrategy: 'replace' as const
      })
    )
    for (const move of request.moves) {
      const listing = byNewKey.get(normalizeHookTrustKeyForLookup(move.newKey))!

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Verify the hooks.json write actually persisted the new keys (read the file back).
  2. Ensure reloadUserConfig / codex config reload ran so hooks/list reflects the new state.
  3. Confirm newKey values don't collide with pre-existing hook keys.
  4. Check that normalizeHookTrustKeyForLookup and the command string still match what codex reports post-mutation.
  5. Retry the repair once the file is stable and reloaded.
Defensive patterns

Strategy: try-catch

Validate before calling

// After the hooks.json mutation, verify the write persisted before calling repair:
const { config } = readHooksJsonWithRaw(hooksJsonPath)
const allNewKeysPresent = request.moves.every((m) =>
  Object.values(config?.hooks ?? {}).flat().some((h) => normalizeKey(h) === normalizeHookTrustKeyForLookup(m.newKey)))
if (!allNewKeysPresent) {
  // abort repair; the mutation didn't land
}

Try / catch

try {
  await runCodexUserHookTrustRebaseSession(request)
} catch (error) {
  if (error instanceof Error && error.message.startsWith('post-mutation hooks/list reported')) {
    // confirm reloadUserConfig applied; retry after codex reloads config
  } else throw error
}

Prevention

When it happens

Trigger: The hooks.json write that moved hooks to newKey didn't take effect (write failed silently, codex didn't reload, file generation changed); a hook's newKey collides with an existing key; codex normalized the new key differently than expected; the matching command drifted.

Common situations: assertHooksJsonGeneration aborted the write due to a concurrent edit; config/reload didn't pick up the change; codex reports the relocated hook under a transformed key; a second hook already occupied the new key.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/09aa7b832f1070e9. Report an issue: GitHub.