{"record":{"id":"09aa7b832f1070e9","repo":"stablyai/orca","slug":"post-mutation-hooks-list-reported-bynewkey-size","errorCode":null,"errorMessage":"post-mutation hooks/list reported ${byNewKey.size} of ${request.moves.length} moved user hooks","messagePattern":"post-mutation hooks/list reported (.+?) of (.+?) moved user hooks","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/codex/codex-user-hook-trust-rebase-client.ts","lineNumber":137,"sourceCode":"        return {\n          ...move,\n          reportedOldKey: listing.key,\n          wasTrusted: listing.trustStatus === 'trusted',\n          enabled: listing.enabled\n        }\n      })\n    }\n  })\n}\n\nasync function repairUserHookTrust(\n  request: CodexUserHookTrustRepairRequest\n): Promise<CodexUserHookTrustRebaseResult> {\n  return runCodexAppServerSession(request.invocation, async ({ request: requestRpc }) => {\n    const result = await requestRpc('hooks/list', { cwds: [request.hooksListCwd] })\n    const byNewKey = matchingListings(collectCodexHookListings(result), request.moves, 'newKey')\n    if (byNewKey.size !== request.moves.length) {\n      throw new Error(\n        `post-mutation hooks/list reported ${byNewKey.size} of ${request.moves.length} moved user hooks`\n      )\n    }\n\n    const keysToClear = new Set([\n      ...request.moves.map((move) => move.reportedOldKey),\n      ...Array.from(byNewKey.values(), (listing) => listing.key)\n    ])\n    const edits: { keyPath: string; value: unknown; mergeStrategy: 'replace' }[] = Array.from(\n      keysToClear,\n      (key) => ({\n        keyPath: quotedKeyPath(key),\n        value: null,\n        mergeStrategy: 'replace' as const\n      })\n    )\n    for (const move of request.moves) {\n      const listing = byNewKey.get(normalizeHookTrustKeyForLookup(move.newKey))!","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/codex/codex-user-hook-trust-rebase-client.ts#L119-L155","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the hooks.json write actually persisted the new keys (read the file back).","Ensure reloadUserConfig / codex config reload ran so hooks/list reflects the new state.","Confirm newKey values don't collide with pre-existing hook keys.","Check that normalizeHookTrustKeyForLookup and the command string still match what codex reports post-mutation.","Retry the repair once the file is stable and reloaded."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// After the hooks.json mutation, verify the write persisted before calling repair:\nconst { config } = readHooksJsonWithRaw(hooksJsonPath)\nconst allNewKeysPresent = request.moves.every((m) =>\n  Object.values(config?.hooks ?? {}).flat().some((h) => normalizeKey(h) === normalizeHookTrustKeyForLookup(m.newKey)))\nif (!allNewKeysPresent) {\n  // abort repair; the mutation didn't land\n}","typeGuard":null,"tryCatchPattern":"try {\n  await runCodexUserHookTrustRebaseSession(request)\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith('post-mutation hooks/list reported')) {\n    // confirm reloadUserConfig applied; retry after codex reloads config\n  } else throw error\n}","preventionTips":["Ensure config/reload runs so hooks/list reflects the mutated file.","Confirm newKey values don't collide with existing hook keys.","Re-run inspect to capture fresh state before retrying repair.","Keep normalizeHookTrustKeyForLookup aligned with codex's key normalization."],"tags":["codex","hooks","trust-rebase","json-rpc","consistency","post-mutation"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}