{"record":{"id":"2a4fc23ea65a274a","repo":"paperclipai/paperclip","slug":"codex-startup-trust-invalid-project","errorCode":"codex_startup_trust_invalid_project","errorMessage":"codex_startup_trust_invalid_project","messagePattern":"codex_startup_trust_invalid_project","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/drivers/codex/codex-startup-trust.ts","lineNumber":108,"sourceCode":"  }\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 {\n    rmSync(temporary, { force: true });\n  }\n}\n","sourceCodeStart":90,"sourceCodeEnd":123,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/drivers/codex/codex-startup-trust.ts#L90-L123","documentation":"After validating the projects map, the function reads the entry for the resolved trust root and requires it to be a plain object so it can spread and add trust_level. It throws this error when projects[root] is a scalar, array, or Date instead of a table.","triggerScenarios":"config.toml contains an entry like projects.\"/repo\" = true (or a string/number/array) instead of a [projects.\"/repo\"] table, for the exact resolved repo root path.","commonSituations":"Manual trust edits writing a boolean flag, older Codex formats storing project settings as scalars, path mismatches after symlinks changing the root key so an unexpected entry is read.","solutions":["Edit config.toml so the entry for the repo root is a table: [projects.\"<abs-root>\"] with trust_level inside it.","Delete the malformed projects key and let the driver recreate it as trusted.","Verify the resolved root (realpath of cwd) matches the key you edited — symlinks can change which entry is read.","Regenerate a clean config.toml from scratch if multiple entries are malformed."],"exampleFix":"// before (config.toml)\n[projects]\n\"/repo\" = true\n// after (config.toml)\n[projects.\"/repo\"]\ntrust_level = \"trusted\"","handlingStrategy":"type-guard","validationCode":"const entry = readParsedConfig().projects?.[realpathSync(cwd)];\nif (entry !== undefined && !(typeof entry === 'object' && entry !== null && !Array.isArray(entry) && !(entry instanceof Date))) throw new Error(`projects[\"${cwd}\"] must be a table, got ${typeof entry}`);","typeGuard":"const isProjectTable = (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_project') { rewriteProjectEntryAsTable(root); trustCodexStartupRoot(codexHome, cwd); } else throw e; }","preventionTips":["Write trust entries as [projects.\"<abs-root>\"] tables with trust_level inside","Check for symlink/realpath differences between the key you set and the resolved root","Lint ~/.codex/config.toml after manual edits or Codex CLI upgrades","One machine-writer per config file to avoid competing formats"],"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-14T05:17:10.506Z"}