{"record":{"id":"0e785f399825c7d7","repo":"stablyai/orca","slug":"runtime-error","errorCode":"runtime_error","errorMessage":"Could not read ${dataPath}: ${error instanceof Error ? error.message : String(error)}","messagePattern":"Could not read (.+?): (.+?)","errorType":"exception","errorClass":"RuntimeClientError","httpStatus":null,"severity":"error","filePath":"src/cli/handlers/agent-hooks.ts","lineNumber":47,"sourceCode":"  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\n  } finally {\n    if (!renamed && existsSync(tmpPath)) {\n      try {\n        unlinkSync(tmpPath)","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/cli/handlers/agent-hooks.ts#L29-L65","documentation":"Wrapped RuntimeClientError (code 'runtime_error') thrown by readPersistedState when reading/parsing the agent-hooks state file throws for any reason — a JSON SyntaxError, the not-an-object inner Error (538), or a filesystem read error. It prefixes the message with the dataPath and the underlying error message so the user knows which file failed and why. The original cause is stringified into the message (not chained via .cause).","triggerScenarios":"existsSync(dataPath) is true but readFileSync throws (permissions, EISDIR), or JSON.parse throws (truncated/corrupt JSON), or the parsed value is not a record (inner throw at 538).","commonSituations":"Corrupt or truncated state file (crash mid-write before the atomic rename), permissions changed on the file, the path points at a directory, or a partial write from a killed process.","solutions":["Read the embedded underlying message to classify: SyntaxError => corrupt JSON, EACCES => permissions, EISDIR => path is a dir.","Back up then delete the corrupt file so the next run regenerates defaults.","Fix permissions/ownership on the file if the cause is EACCES.","Confirm writePersistedState's atomic-rename path is on the same filesystem to avoid partial writes."],"exampleFix":"// before: corrupt ~/.config/orca/agent-hooks.json -> runtime_error\n\n// after\nmv ~/.config/orca/agent-hooks.json ~/.config/orca/agent-hooks.json.bak\n# next run recreates a valid default state","handlingStrategy":"try-catch","validationCode":"import { readFileSync, existsSync, statSync } from 'node:fs'\n\nfunction safeReadState(dataPath: string): string {\n  if (!existsSync(dataPath)) throw new Error('missing')\n  const st = statSync(dataPath)\n  if (!st.isFile()) throw new Error(`${dataPath} is not a regular file`)\n  return readFileSync(dataPath, 'utf-8')\n}","typeGuard":"function isRuntimeClientError(e: unknown): e is RuntimeClientError {\n  return e instanceof RuntimeClientError\n}","tryCatchPattern":"try {\n  readPersistedState(dataPath)\n} catch (e) {\n  if (e instanceof RuntimeClientError && e.code === 'runtime_error') {\n    // back up and delete corrupt file so defaults regenerate\n    // renameSync(dataPath, dataPath + '.bak')\n  }\n  throw e\n}","preventionTips":["Back up state files before destructive edits.","Ensure writePersistedState's atomic temp+rename stays on the same filesystem to avoid partial writes.","Run validation/recovery on corrupt state instead of crashing."],"tags":["agent-hooks","persistence","json","filesystem","runtime-error"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}