{"record":{"id":"9b027b6ad1092992","repo":"paperclipai/paperclip","slug":"codex-startup-trust-invalid-projects","errorCode":"codex_startup_trust_invalid_projects","errorMessage":"codex_startup_trust_invalid_projects","messagePattern":"codex_startup_trust_invalid_projects","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/drivers/codex/codex-startup-trust.ts","lineNumber":101,"sourceCode":"    for (let ancestor = startup; ; ancestor = dirname(ancestor)) {\n      if (existsSync(join(ancestor, \".git\")))\n        throw new Error(\"codex_startup_trust_git_resolution_failed\", {\n          cause: error,\n        });\n      if (dirname(ancestor) === ancestor) break;\n    }\n  }\n  mkdirSync(codexHome, { recursive: true, mode: 0o700 });\n  const path = join(codexHome, \"config.toml\");\n  const source = existsSync(path) ? readFileSync(path, \"utf8\") : \"\";\n  const config = parse(source);\n  const projects = config.projects ?? {};\n  if (\n    typeof projects !== \"object\" ||\n    Array.isArray(projects) ||\n    projects instanceof Date\n  )\n    throw new Error(\"codex_startup_trust_invalid_projects\");\n  const project = projects[root] ?? {};\n  if (\n    typeof project !== \"object\" ||\n    Array.isArray(project) ||\n    project instanceof Date\n  )\n    throw new Error(\"codex_startup_trust_invalid_project\");\n  config.projects = {\n    ...projects,\n    [root]: { ...project, trust_level: \"trusted\" },\n  };\n  const updated = editTrust(source, root, config);\n  if (updated === source) return;\n  const temporary = resolve(codexHome, `config.toml.${randomUUID()}.tmp`);\n  try {\n    writeFileSync(temporary, updated, { mode: 0o600, flag: \"wx\" });\n    renameSync(temporary, path);\n  } finally {","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/drivers/codex/codex-startup-trust.ts#L83-L119","documentation":"Before writing trust_level, the function parses the existing config.toml into a structured config and validates that the projects section is a plain object. It throws this error when config.projects exists but is an array, a Date, or otherwise not a normal object, because it cannot safely merge trust entries into that shape.","triggerScenarios":"A hand-edited or corrupted ~/.codex/config.toml where [projects] resolves to a non-object value (e.g. projects = [] or a TOML table array of projects), or a parser returning Date-wrapped values.","commonSituations":"Users pasting invalid TOML, older Codex config formats using an array of project entries, automated writers corrupting the file, shared dotfiles synced between machines.","solutions":["Open codexHome/config.toml and fix the projects section to be a proper TOML table keyed by absolute paths.","Back up and remove/repair the malformed config.toml so a fresh one can be written.","Validate the parsed config with a schema check before running the driver to catch the corruption early.","Upgrade/align the Codex CLI version so its config format matches what the parser expects."],"exampleFix":"// before (config.toml)\nprojects = [\"/repo\"]\n// after (config.toml)\n[projects.\"/repo\"]\ntrust_level = \"trusted\"","handlingStrategy":"validation","validationCode":"function projectsIsPlainObject(config: unknown): boolean {\n  const p = (config as { projects?: unknown })?.projects;\n  return p === undefined || (typeof p === 'object' && p !== null && !Array.isArray(p) && !(p instanceof Date));\n}","typeGuard":"const isPlainRecord = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v) && !(v instanceof Date);","tryCatchPattern":"try { trustCodexStartupRoot(codexHome, cwd); } catch (e) { if ((e as Error).message === 'codex_startup_trust_invalid_projects') { backupConfigToml(); resetProjectsSection(); trustCodexStartupRoot(codexHome, cwd); } else throw e; }","preventionTips":["Never hand-edit [projects] as a TOML array; key it by absolute paths","Back up ~/.codex/config.toml before manual edits or syncing dotfiles","Validate config.toml parses to the expected shape after any external writer touches it","Keep the Codex CLI version aligned with the config format the driver parses"],"tags":["codex","config","validation","toml"],"backgroundTag":"config-type-mismatch","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}