nanocoai/nanoclaw · error · StdinJsonInputError

--stdin-json input exceeds ${MAX_STDIN_JSON_BYTES} bytes

Error message

--stdin-json input exceeds ${MAX_STDIN_JSON_BYTES} bytes

What it means

Thrown when the gateway provider composes auxiliary containers (e.g. a sidecar proxy) in the session spec, but the selected container driver does not declare the auxiliaryContainers capability. Composition checks this up front so the failure names the mismatched sides rather than surfacing later as a driver refusal backstop.

Source

Thrown at container/agent-runner/src/cli/stdin-json.ts:54

 * therefore normalized to a Buffer and the running total counts
 * `buffer.byteLength` — the true encoded size — rather than string length,
 * where a multibyte character (e.g. "ש", 2 bytes) would count as 1.
 *
 * Decoding to text happens exactly once, after the whole input is collected:
 * a chunk boundary can fall in the middle of a multibyte character, so
 * decoding chunk-by-chunk could corrupt the character that straddles the
 * split. The limit check runs before buffering grows past the cap, so an
 * oversized (or unbounded) pipe is rejected without being read to the end.
 */
async function readBounded(stream: StdinJsonStream): Promise<string> {
  const chunks: Buffer[] = [];
  let byteLength = 0;

  for await (const chunk of stream) {
    const buffer = typeof chunk === 'string' ? Buffer.from(chunk, 'utf8') : Buffer.from(chunk);
    byteLength += buffer.byteLength;
    if (byteLength > MAX_STDIN_JSON_BYTES) {
      throw new StdinJsonInputError(`--stdin-json input exceeds ${MAX_STDIN_JSON_BYTES} bytes`);
    }
    chunks.push(buffer);
  }

  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 });

View on GitHub (pinned to 294ef2aee8)

Solutions

  1. Switch the session's driver to one that declares auxiliaryContainers in its capabilities()
  2. Disable or reconfigure the gateway provider so it composes no auxiliary containers
  3. If writing a custom driver, implement auxiliary container management and return auxiliaryContainers: true from capabilities()

Example fix

// before
const driver = getDriver('docker');
await spawnContainer({ agentGroup, gateway, driver }); // gateway composes sidecars

// after
const driver = getDriver('gateway-aware'); // capabilities().auxiliaryContainers === true
if (gateway.containers?.length && !driver.capabilities().auxiliaryContainers) throw new Error('pick another driver');
await spawnContainer({ agentGroup, gateway, driver });
Defensive patterns

Strategy: validation

Validate before calling

if (gateway.containers?.length && !driver.capabilities().auxiliaryContainers) {
  throw new Error(`driver '${driver.kind}' cannot manage gateway auxiliary containers`);
}
await spawnContainer({ agentGroup, gateway, driver });

Type guard

function driverManagesAuxiliaries(d: Driver): boolean {
  return d.capabilities().auxiliaryContainers === true;
}

Prevention

When it happens

Trigger: spawnContainer() is called with a gateway provider that returns containers beyond the agent role (gateway.containers?.length > 0) while driver.capabilities().auxiliaryContainers is false (e.g. the docker driver).

Common situations: Switching an agent group to a gateway-based provider (needing a sidecar) while still using the default docker driver; upgrading to a provider that now composes auxiliary containers without updating the driver.

Related errors


AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28). Data as JSON: /api/errors/152dd349a09a7a3c. Report an issue: GitHub.