{"record":{"id":"78cff5c5ef920897","repo":"nanocoai/nanoclaw","slug":"stdin-json-input-is-empty","errorCode":null,"errorMessage":"--stdin-json input is empty","messagePattern":"--stdin-json input is empty","errorType":"validation","errorClass":"StdinJsonInputError","httpStatus":null,"severity":"error","filePath":"container/agent-runner/src/cli/stdin-json.ts","lineNumber":65,"sourceCode":"  const chunks: Buffer[] = [];\n  let byteLength = 0;\n\n  for await (const chunk of stream) {\n    const buffer = typeof chunk === 'string' ? Buffer.from(chunk, 'utf8') : Buffer.from(chunk);\n    byteLength += buffer.byteLength;\n    if (byteLength > MAX_STDIN_JSON_BYTES) {\n      throw new StdinJsonInputError(`--stdin-json input exceeds ${MAX_STDIN_JSON_BYTES} bytes`);\n    }\n    chunks.push(buffer);\n  }\n\n  return Buffer.concat(chunks, byteLength).toString('utf8');\n}\n\n/** Parse the input, requiring exactly one JSON object — not an array, scalar, or null. */\nfunction parseJsonObject(source: string): Record<string, unknown> {\n  if (source.trim().length === 0) {\n    throw new StdinJsonInputError('--stdin-json input is empty');\n  }\n\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(source);\n  } catch (err) {\n    throw new StdinJsonInputError('--stdin-json input is not valid JSON', { cause: err });\n  }\n\n  if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n    throw new StdinJsonInputError('--stdin-json input must be one JSON object');\n  }\n\n  return parsed as Record<string, unknown>;\n}\n\n/** Match the key normalization applied by command parsers in crud.ts. */\nfunction canonicalArgKey(key: string): string {","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/container/agent-runner/src/cli/stdin-json.ts#L47-L83","documentation":"composeSessionSpec refuses to build a spec whose group folder name is not a legal Kubernetes/Docker label value (<=63 bytes of [A-Za-z0-9._-], alphanumeric at both ends), because admission joins on the group-folder label verbatim and never projects it. Failing here, non-retryably, prevents an admission-side check from mis-comparing against a truncated hash stand-in and denying every session of the group.","triggerScenarios":"composeSessionSpec() called with agentGroup.folder containing uppercase, spaces, slashes, leading/trailing dots or hyphens, or exceeding 63 bytes.","commonSituations":"A group folder created with a human-friendly name like 'My Agent Group' or 'agent/group'; folders inherited from older installs that predate the label constraint.","solutions":["Rename the group folder to match [a-z0-9._-] with alphanumeric ends and <=63 bytes","Run `bun scripts/detect-driver-migration.ts` to enumerate affected groups and apply the suggested fix","Update the agent_groups row's folder field to the renamed folder"],"exampleFix":"// before\nagentGroup.folder = 'My Agent Group';\nconst spec = composeSessionSpec({ agentGroup, ... });\n\n// after\nagentGroup.folder = 'my-agent-group';\nconst spec = composeSessionSpec({ agentGroup, ... });","handlingStrategy":"validation","validationCode":"const LABEL_RE = /^[A-Za-z0-9]([A-Za-z0-9._-]{0,61}[A-Za-z0-9])?$/;\nif (!LABEL_RE.test(agentGroup.folder) || agentGroup.folder.length > 63) {\n  throw new Error(`group folder '${agentGroup.folder}' is not a legal label value; rename it`);\n}\nconst spec = composeSessionSpec({ agentGroup, ... });","typeGuard":"function isLegalLabelValue(v: string): boolean {\n  return /^[A-Za-z0-9]([A-Za-z0-9._-]{0,61}[A-Za-z0-9])?$/.test(v) && v.length <= 63;\n}","tryCatchPattern":null,"preventionTips":["Create group folders with lowercase kebab-case names from the start","Run `bun scripts/detect-driver-migration.ts` after renames or upgrades"],"tags":["docker-labels","group-folder","spec-validation","container-runner"],"backgroundTag":"label-value-validation-failed","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}