nanocoai/nanoclaw · error · StdinJsonInputError
--stdin-json input must be one JSON object
Error message
--stdin-json input must be one JSON object
What it means
Second guard in parseMemoryMb: the value matched the size grammar but the numeric part is not finite (Number(match[1]) is NaN/Infinity). Practically hard to reach via the regex, but it keeps the parse total function and still fails closed rather than dropping the operator's memory cap.
Source
Thrown at container/agent-runner/src/cli/stdin-json.ts:76
return Buffer.concat(chunks, byteLength).toString('utf8');
}
/** Parse the input, requiring exactly one JSON object — not an array, scalar, or null. */
function parseJsonObject(source: string): Record<string, unknown> {
if (source.trim().length === 0) {
throw new StdinJsonInputError('--stdin-json input is empty');
}
let parsed: unknown;
try {
parsed = JSON.parse(source);
} catch (err) {
throw new StdinJsonInputError('--stdin-json input is not valid JSON', { cause: err });
}
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
throw new StdinJsonInputError('--stdin-json input must be one JSON object');
}
return parsed as Record<string, unknown>;
}
/** Match the key normalization applied by command parsers in crud.ts. */
function canonicalArgKey(key: string): string {
return key.replace(/-/g, '_');
}
/**
* Reject any stdin key that could collide with another arg after the merge.
*
* Command parsers (crud.ts) normalize `-` to `_` in arg keys, so `group-id`
* and `group_id` are the same argument downstream. Two keys that are distinct
* here but identical after normalization would silently overwrite each other
* past this point — so every such alias is a hard conflict, whether the pair
* is stdin-vs-argv or two stdin keys.View on GitHub (pinned to 294ef2aee8)
Solutions
- Use a realistic finite value like 8g or 4096m
- If you need 'no cap', set CONTAINER_MEMORY_LIMIT=0
- Audit .env generation scripts that compute the limit
Example fix
# before CONTAINER_MEMORY_LIMIT=999999999999999999999999999999g # after CONTAINER_MEMORY_LIMIT=8g
Defensive patterns
Strategy: validation
Validate before calling
const raw = process.env.CONTAINER_MEMORY_LIMIT;
if (raw) {
const m = /^(\d+(?:\.\d+)?)\s*([bkmg]?)b?$/i.exec(raw.trim());
if (!m || !Number.isFinite(Number(m[1]))) throw new Error('bad CONTAINER_MEMORY_LIMIT');
} Type guard
function isFiniteDockerSize(v: string): boolean {
const m = /^(\d+(?:\.\d+)?)\s*([bkmg]?)b?$/i.exec(v.trim());
return !!m && Number.isFinite(Number(m[1]));
} Prevention
- Don't script-generate memory limits without clamping magnitude
- Prefer short human-scale values (8g, 4096m)
When it happens
Trigger: composeSessionSpec() parses a CONTAINER_MEMORY_LIMIT whose numeric component converts to a non-finite Number — e.g. an astronomically long digit string that overflows to Infinity.
Common situations: Script-generated env values, a pasted number with hundreds of digits, or edge-case fuzzing of the env var.
Related errors
- --stdin-json input is not valid JSON
- --stdin-json input exceeds ${MAX_STDIN_JSON_BYTES} bytes
- wakeContainer failed — host-sweep will retry
- Failed to list existing sessions for adoption
- Failed to clean up orphaned containers
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/f3c3b4a38657f4a3.
Report an issue: GitHub.