{"record":{"id":"6e59a4d9e9db928a","repo":"nexu-io/open-design","slug":"invalid-json-in-filepath-message","errorCode":null,"errorMessage":"invalid JSON in ${filePath}: ${message}","messagePattern":"invalid JSON in (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/daemon/src/artifacts-cli.ts","lineNumber":98,"sourceCode":"      options.encoding = value;\n    } else if (arg === '-h' || arg === '--help') {\n      options.help = true;\n    } else {\n      return { error: `unknown option: ${arg}` };\n    }\n  }\n\n  return options;\n}\n\nasync function readJsonObject(filePath: string): Promise<JsonObject> {\n  const text = await readFile(filePath, 'utf8');\n  let value: unknown;\n  try {\n    value = JSON.parse(text) as unknown;\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error);\n    throw new Error(`invalid JSON in ${filePath}: ${message}`);\n  }\n  if (!value || typeof value !== 'object' || Array.isArray(value)) {\n    throw new Error(`${filePath} must contain a JSON object`);\n  }\n  return value as JsonObject;\n}\n\nexport async function runArtifactsCli(args: string[]): Promise<ArtifactCliResult> {\n  const options = parseOptions(args);\n  if ('error' in options) return fail(options.error);\n  if (options.help || !options.command) {\n    process.stdout.write(USAGE);\n    return { exitCode: options.command ? 0 : 1 };\n  }\n  if (options.command !== 'create') return fail(`unknown artifacts command: ${options.command}`);\n  if (!options.name) return fail('create requires --name <path>');\n  if (!options.inputPath) return fail('create requires --input <file>');\n","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/artifacts-cli.ts#L80-L116","documentation":"Thrown by readJsonObject() in the artifacts CLI when JSON.parse fails on the file pointed to by --manifest. The daemon never sees this; it is a local CLI-side parse guard that fires before any HTTP request is made. The original parser message is appended so the syntax error is visible.","triggerScenarios":"Running `od artifacts create --manifest <path>` where <path> is missing a comma, has a trailing comma, an unquoted key, BOM, or any other JSON syntax error. readJsonObject reads the file as utf8 and calls JSON.parse on the contents.","commonSituations":"Hand-editing a manifest JSON and leaving a syntax error; saving with an editor that inserts a UTF-8 BOM; copy-pasting a manifest from docs that used single quotes; CRLF/inline comments (JSONC) mistakenly treated as JSON.","solutions":["Validate the file with a JSON linter or `node -e \"JSON.parse(require('fs').readFileSync('<path>','utf8'))\"` and fix the reported syntax position.","Re-save the file as plain UTF-8 without BOM and with double-quoted keys.","If you intended to allow comments/trailing commas, switch to strict JSON; the parser does not accept JSONC.","Check the appended ${message} in the error — it names the exact byte offset of the parse failure."],"exampleFix":"// before: manifest.json\n{ kind: \"html\", renderer: \"html\", exports: [\"html\"] }\n\n// after: valid JSON (quoted keys)\n{ \"kind\": \"html\", \"renderer\": \"html\", \"exports\": [\"html\"] }","handlingStrategy":"validation","validationCode":"import { readFileSync } from 'node:fs';\nfunction assertValidManifestFile(p: string) {\n  const text = readFileSync(p, 'utf8');\n  let v: unknown;\n  try { v = JSON.parse(text); } catch (e) {\n    throw new Error(`manifest ${p} is not valid JSON: ${(e as Error).message}`);\n  }\n  if (!v || typeof v !== 'object' || Array.isArray(v)) {\n    throw new Error(`manifest ${p} must be a JSON object`);\n  }\n}\nassertValidManifestFile(manifestPath);","typeGuard":"function isJsonObject(value: unknown): value is Record<string, unknown> {\n  return !!value && typeof value === 'object' && !Array.isArray(value);\n}","tryCatchPattern":"try {\n  const manifest = await readJsonObject(manifestPath);\n} catch (e) {\n  console.error((e as Error).message); // already includes the parse offset\n  process.exit(1);\n}","preventionTips":["Run files through a JSON linter in your editor/CI before invoking the CLI.","Save manifest files as UTF-8 without BOM.","Treat the appended ${message} as the source of truth for the syntax-error position."],"tags":["cli","json","artifacts","validation","input-parsing"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}