{"record":{"id":"6d18975b20edcfcf","repo":"affaan-m/ECC","slug":"gh-args-join-returned-invalid-json-erro-6d1897","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/lib/github-discussions.js","lineNumber":51,"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 discussionNeedsMaintainerTouch(discussion) {\n  if (MAINTAINER_ASSOCIATIONS.has(discussion.authorAssociation)) {\n    return false;\n  }\n\n  if (\n    discussion.answer\n    && MAINTAINER_ASSOCIATIONS.has(discussion.answer.authorAssociation)\n  ) {\n    return false;\n  }\n\n  const comments = discussion.comments && Array.isArray(discussion.comments.nodes)\n    ? discussion.comments.nodes\n    : [];","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/github-discussions.js#L33-L69","documentation":"Thrown by runGhJson() in scripts/lib/github-discussions.js when the gh command exited zero but its stdout was not valid JSON. The wrapper expects gh api --jq or graphql output to be parseable; anything else (text, HTML, empty) triggers this error.","triggerScenarios":"runGhJson calls runCommand successfully (status 0), then JSON.parse(stdout || 'null') throws. Happens when gh prints a human-readable message, a warning interleaved with JSON, an empty string with garbage, or when ECC_GH_SHIM emits non-JSON stdout.","commonSituations":"gh CLI version prints a deprecation notice on stdout before the JSON; shim script forgets to JSON.stringify its result; wrong gh subcommand returned plain text; paging footer or 'Processing...' line leaked into stdout; gh wrote logs to stdout instead of stderr.","solutions":["Reproduce manually: gh api graphql -f query=... --jq '.' and inspect the raw stdout.","If gh prints warnings on stdout, upgrade gh or redirect stdout filtering; ensure logs go to stderr only.","If using ECC_GH_SHIM, ensure it does console.log(JSON.stringify(payload)) and writes any diagnostics to stderr.","Upgrade gh CLI to a recent stable release."],"exampleFix":"// before\nreturn JSON.parse(stdout || 'null');\n\n// after (defensive trim of leading non-JSON)\nconst trimmed = String(stdout || '').trim();\nif (!trimmed || trimmed[0] !== '{' && trimmed[0] !== '[' && trimmed !== 'null') {\n  throw new Error(`gh ${args.join(' ')} returned non-JSON output: ${trimmed.slice(0, 200)}`);\n}\nreturn JSON.parse(trimmed);","handlingStrategy":"validation","validationCode":"function looksJson(s) {\n  const t = String(s || '').trim();\n  return t === 'null' || t.startsWith('{') || t.startsWith('[');\n}\nconst stdout = runCommand(cmd, args, opts);\nif (!looksJson(stdout)) {\n  throw new Error(`Expected JSON from ${cmd}; got: ${stdout.slice(0, 200)}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  return JSON.parse(stdout || 'null');\n} catch (err) {\n  if (/Unexpected token|JSON/.test(err.message)) {\n    throw new Error(`gh ${args.join(' ')} returned non-JSON: ${stdout.slice(0, 200)}`);\n  }\n  throw err;\n}","preventionTips":["Pin gh CLI to a stable version that emits machine-readable JSON only.","If writing a shim (ECC_GH_SHIM), always JSON.stringify the result and log to stderr.","Add a smoke test that runs the exact gh query and asserts JSON.parse works."],"tags":["github","json","parsing","process"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}