{"record":{"id":"89420b3b8cfb28aa","repo":"nexu-io/open-design","slug":"vela-command-returned-invalid-json-detail","errorCode":null,"errorMessage":"Vela ${command} returned invalid JSON: ${detail}","messagePattern":"Vela (.+?) returned invalid JSON: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/media/vela.ts","lineNumber":88,"sourceCode":"\nfunction isRecord(value: unknown): value is JsonRecord {\n  return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction parseJsonObject(stdout: string, command: string): JsonRecord {\n  const trimmed = stdout.trim();\n  if (!trimmed) {\n    throw new Error(`Vela ${command} returned no JSON output`);\n  }\n  try {\n    const value: unknown = JSON.parse(trimmed);\n    if (!isRecord(value)) {\n      throw new Error('expected a JSON object');\n    }\n    return value;\n  } catch (error) {\n    const detail = error instanceof Error ? error.message : String(error);\n    throw new Error(`Vela ${command} returned invalid JSON: ${detail}`);\n  }\n}\n\nfunction nonEmptyString(value: unknown): string | null {\n  return typeof value === 'string' && value.trim() ? value.trim() : null;\n}\n\nfunction positiveIntegerFromEnv(name: string, fallback: number): number {\n  const parsed = Number(process.env[name]);\n  return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback;\n}\n\nfunction wireModelForVela(model: string, wireModel: string): string {\n  // A configured OD alias is already the provider-facing wire name. Only\n  // remove the catalogue namespace when the alias layer left the id intact.\n  if (wireModel !== model) return wireModel;\n  return model.startsWith('vela/') ? model.slice('vela/'.length) : model;\n}","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/media/vela.ts#L70-L106","documentation":"Thrown by parseJsonObject() when stdout is non-empty but JSON.parse fails or the parsed value is not a JSON object (e.g. it is an array or primitive). The detail from the parse error or the 'expected a JSON object' message is appended. This distinguishes malformed-JSON failures from empty-output failures (error 484).","triggerScenarios":"Vela CLI emits non-JSON text (a banner, log line, partial JSON, or an error message) on stdout, or emits valid JSON that is an array/scalar rather than an object.","commonSituations":"Vela CLI prints a human-readable error or progress line to stdout before/instead of JSON; CLI version change altered the output shape; a proxy or wrapper around the Vela binary injects text; the CLI emitted a JSON array for a command the daemon expects to return an object.","solutions":["Run the failing Vela command directly and capture stdout to see the non-JSON content","Upgrade or pin the Vela CLI version to one that emits a clean JSON object for that subcommand","Ensure no shell wrapper or RC file prints to stdout when the Vela binary runs","If the CLI emits logs on stdout, redirect them to stderr in the command runner"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"function looksLikeJsonObject(stdout: string): boolean {\n  const t = stdout.trim();\n  return t.startsWith('{') && t.endsWith('}');\n}\n\nconst stdout = await runCommand(args, opts);\nif (!looksLikeJsonObject(stdout)) {\n  throw new Error(`Vela ${label} stdout is not a JSON object: ${stdout.slice(0, 120)}`);\n}","typeGuard":"function isJsonRecord(value: unknown): value is Record<string, unknown> {\n  return value !== null && typeof value === 'object' && !Array.isArray(value);\n}","tryCatchPattern":"try {\n  const value: unknown = JSON.parse(stdout);\n  if (!isJsonRecord(value)) throw new Error('expected a JSON object');\n} catch (err) {\n  // log the raw stdout for schema diagnosis, then rethrow\n  throw err;\n}","preventionTips":["Ensure no shell RC files or wrappers print to stdout when the Vela binary runs","Pin the Vela CLI version so output schema changes do not surprise the parser","After Vela upgrades, replay a recorded trace through the mock CLI to confirm the JSON shape round-trips"],"tags":["vela","cli","json","parsing","upstream"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}