{"record":{"id":"831627542835c775","repo":"affaan-m/ECC","slug":"gh-args-join-returned-invalid-json-erro-831627","errorCode":null,"errorMessage":"gh ${args.join(' ')} returned invalid JSON: ${error.message}","messagePattern":"gh (.+?) returned invalid JSON: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/platform-audit.js","lineNumber":258,"sourceCode":"\n  return result.stdout || '';\n}\n\nfunction runGhJson(args, options = {}) {\n  const shimPath = process.env.ECC_GH_SHIM;\n  const command = shimPath ? process.execPath : 'gh';\n  const commandArgs = shimPath ? [shimPath, ...args] : args;\n  const env = { ...process.env };\n\n  if (!options.useEnvGithubToken) {\n    delete env.GITHUB_TOKEN;\n  }\n\n  const stdout = runCommand(command, commandArgs, { env });\n  try {\n    return JSON.parse(stdout || 'null');\n  } catch (error) {\n    throw new Error(`gh ${args.join(' ')} returned invalid JSON: ${error.message}`);\n  }\n}\n\nfunction readText(rootDir, relativePath) {\n  try {\n    return fs.readFileSync(path.join(rootDir, relativePath), 'utf8');\n  } catch (_error) {\n    return '';\n  }\n}\n\nfunction fileExists(rootDir, relativePath) {\n  return fs.existsSync(path.join(rootDir, relativePath));\n}\n\nfunction safeParseJson(text) {\n  if (!text || !text.trim()) {\n    return null;","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/platform-audit.js#L240-L276","documentation":"Thrown by runGhJson in platform-audit when a `gh ... --json ...` call succeeds (exit 0) but its stdout is not valid JSON. The wrapper expects gh's structured output; a parse failure means gh emitted something unexpected (warnings on stdout, a non-JSON error page, a shim that logged prose). The raw JSON.parse error message is appended for diagnosis.","triggerScenarios":"A custom ECC_GH_SHIM prints logs to stdout instead of stderr; gh emits a deprecation/rate-limit notice before the JSON; gh version returns a different shape; stdout buffering concatenated two responses; the shim exits 0 but wrote text.","commonSituations":"Shim logging misconfigured to stdout; gh CLI upgraded and changed output; a proxy/wrapper altered the stream; locale/encoding inserted a BOM or CRLF.","solutions":["Run the exact gh command manually and inspect stdout — anything before the JSON must move to stderr.","If using ECC_GH_SHIM, ensure it writes only JSON to stdout and all logs to stderr.","Upgrade or pin gh to a version whose `--json` output is stable; check `gh --version`.","Unset ECC_GH_SHIM to use the real gh binary and rule out the shim."],"exampleFix":"// before — shim logs to stdout, breaking JSON.parse\nconst stdout = runCommand(command, commandArgs, { env });\nreturn JSON.parse(stdout || 'null');\n// after — shim must log to stderr; meanwhile strip leading non-JSON lines\nconst stdout = runCommand(command, commandArgs, { env });\nconst jsonStart = stdout.indexOf(/^\\{|^\\[/m.test(stdout) ? stdout.search(/[{[]/) : 0);\nreturn JSON.parse(stdout.slice(jsonStart) || 'null');","handlingStrategy":"try-catch","validationCode":"// Detect whether stdout is JSON-shaped before parsing\nfunction looksLikeJson(stdout) {\n  const s = String(stdout || '').trim();\n  return s.startsWith('{') || s.startsWith('[');\n}","typeGuard":"function isJsonObjectOrArray(value) {\n  return value !== null && typeof value === 'object';\n}","tryCatchPattern":"let data;\ntry {\n  data = JSON.parse(stdout || 'null');\n} catch (error) {\n  throw new Error(`gh ${args.join(' ')} returned invalid JSON: ${error.message}`);\n}\nreturn data;","preventionTips":["Keep all shim logging on stderr; stdout must carry JSON only.","Pin gh to a version with stable --json output.","Unset ECC_GH_SHIM to test against real gh when diagnosing.","Inspect raw stdout manually when this fires to find the polluting text."],"tags":["gh","json","platform-audit","shim"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}