{"record":{"id":"57c7dbe50b271518","repo":"garrytan/gstack","slug":"gbrain-sources-list-returned-non-json-output-e","errorCode":null,"errorMessage":"gbrain sources list returned non-JSON output: ${(err as Error).message}","messagePattern":"gbrain sources list returned non-JSON output: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/gbrain-sources.ts","lineNumber":143,"sourceCode":"      shell: NEEDS_SHELL_ON_WINDOWS, // #1731: gbrain is a .cmd shim on Windows\n    });\n  } catch (err) {\n    const e = err as NodeJS.ErrnoException & { stderr?: Buffer };\n    const stderr = e.stderr?.toString() || \"\";\n    if (e.code === \"ENOENT\" || stderr.includes(\"command not found\")) {\n      throw new Error(\"gbrain CLI not on PATH\");\n    }\n    if (stderr.includes(\"Cannot connect to database\") || stderr.includes(\"config.json\")) {\n      throw new Error(\"gbrain not configured (run /setup-gbrain)\");\n    }\n    throw err;\n  }\n\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(stdout);\n  } catch (err) {\n    throw new Error(`gbrain sources list returned non-JSON output: ${(err as Error).message}`);\n  }\n\n  const sources = parseSourcesList(parsed);\n  const match = sources.find((s) => s.id === id);\n  if (!match) return { status: \"absent\" };\n  return {\n    status: \"match\",\n    registered_path: match.local_path,\n  };\n}\n\n/**\n * Ensure source <id> is registered at <path>. Idempotent.\n *\n * Behavior:\n *   - status=absent  → `gbrain sources add <id> --path <path> [--federated]`, returns changed=true.\n *   - status=match + same path → no-op, returns changed=false.\n *   - status=match + different path → `sources remove --confirm-destructive` + `sources add`, returns changed=true.","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/lib/gbrain-sources.ts#L125-L161","documentation":"Thrown by probeSource() when gbrain sources list --json exits successfully and prints to stdout, but JSON.parse(stdout) throws. It captures the parse error message so the developer can see what tripped the parser. This is distinct from 316 (no binary), 317 (DB/config), and 315 (no JSON emitted at all) — here stdout exists but is not valid JSON.","triggerScenarios":"gbrain sources list --json exits 0 with stdout containing non-JSON text (e.g. a log line before the JSON, a warning, an incomplete buffer, or a human-format table because --json was ignored). JSON.parse throws and the catch wraps it.","commonSituations":"gbrain version that prints a deprecation/log line to stdout before the JSON; --json flag ignored in an older version so human text is emitted; stdout truncated by a buffer limit or pipe closure; a plugin injected non-JSON output.","solutions":["Run `gbrain sources list --json` manually and inspect the raw stdout to see what preceded the JSON.","Upgrade gbrain to a version that emits clean JSON on stdout with logs on stderr.","If a log line is the culprit, configure gbrain's log level to suppress stdout logging.","Pipe through a JSON extractor if a workaround is needed before upgrading."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import { execFileSync } from 'child_process';\nfunction gbrainStdoutIsJson(env: NodeJS.ProcessEnv = process.env): boolean {\n  try {\n    const out = execFileSync('gbrain', ['sources', 'list', '--json'], { encoding: 'utf-8', env, timeout: 5_000 });\n    JSON.parse(out); return true;\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  return probeSource(id, env);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('gbrain sources list returned non-JSON')) {\n    // Upgrade gbrain or redirect its logs off stdout, then retry\n    throw new Error('gbrain emitted non-JSON stdout. Upgrade gbrain and retry.');\n  }\n  throw e;\n}","preventionTips":["Pin a gbrain version that emits clean JSON on stdout.","Configure gbrain to send logs to stderr, not stdout.","Smoke-test `gbrain sources list --json | jq .` after install.","Upgrade gbrain promptly when --json semantics change."],"tags":["gbrain","cli","json","parsing"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}