{"record":{"id":"65e2237216ac8255","repo":"stablyai/orca","slug":"file-does-not-contain-a-json-object","errorCode":null,"errorMessage":"file does not contain a JSON object","messagePattern":"file does not contain a JSON object","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/handlers/agent-hooks.ts","lineNumber":43,"sourceCode":"  statuses: AgentHookInstallStatus[]\n}\n\nfunction getDataPath(): string {\n  return join(getDefaultUserDataPath(), 'orca-data.json')\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction readPersistedState(dataPath: string): PersistedState {\n  if (!existsSync(dataPath)) {\n    return getDefaultPersistedState(homedir())\n  }\n  try {\n    const parsed = JSON.parse(readFileSync(dataPath, 'utf-8'))\n    if (!isRecord(parsed)) {\n      throw new Error('file does not contain a JSON object')\n    }\n    return parsed as PersistedState\n  } catch (error) {\n    throw new RuntimeClientError(\n      'runtime_error',\n      `Could not read ${dataPath}: ${error instanceof Error ? error.message : String(error)}`\n    )\n  }\n}\n\nfunction writePersistedState(dataPath: string, state: PersistedState): void {\n  mkdirSync(dirname(dataPath), { recursive: true })\n  const tmpPath = join(dirname(dataPath), `.${Date.now()}-${randomUUID()}.tmp`)\n  let renamed = false\n  try {\n    writeFileSync(tmpPath, `${JSON.stringify(state, null, 2)}\\n`, 'utf-8')\n    renameSync(tmpPath, dataPath)\n    renamed = true","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/cli/handlers/agent-hooks.ts#L25-L61","documentation":"Thrown inside readPersistedState (then re-wrapped as error 539) when the persisted agent-hooks state file parses as valid JSON but the top-level value is not a plain object — e.g. it is an array, a number, a string, or null. isRecord() rejects arrays and null explicitly, so only a real key-value object passes. This inner Error is caught and converted to a RuntimeClientError with the path context.","triggerScenarios":"The dataPath file contains JSON.parse-able content whose root is an array, primitive, or null. Examples: '[]', '42', '\"hello\"', 'null'. Note malformed JSON throws a SyntaxError instead (still caught at 539).","commonSituations":"User hand-edited the agent-hooks state file and saved an array, an external tool wrote a non-object schema, or a prior version wrote a different top-level shape.","solutions":["Restore the file to a JSON object shape (or delete it to regenerate defaults via getDefaultPersistedState).","Back up the current file, then `rm <dataPath>` so the next run recreates a valid default state.","Validate with `jq empty <file>` and ensure `jq -e 'type==\"object\"' <file>` succeeds."],"exampleFix":"// before: ~/.config/orca/agent-hooks.json contains `[]`\n\n// after: replace with an object, or remove the file\nrm ~/.config/orca/agent-hooks.json","handlingStrategy":"type-guard","validationCode":"import { readFileSync, existsSync } from 'node:fs'\n\nfunction readStateObject(dataPath: string): Record<string, unknown> {\n  if (!existsSync(dataPath)) return {}\n  const parsed = JSON.parse(readFileSync(dataPath, 'utf-8'))\n  if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n    throw new Error(`${dataPath} root is not a JSON object`)\n  }\n  return parsed as Record<string, unknown>\n}","typeGuard":"function isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value)\n}","tryCatchPattern":null,"preventionTips":["Validate persisted files against the expected schema before trusting them.","Keep backups before hand-editing state files."],"tags":["agent-hooks","persistence","json","filesystem"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}