nanocoai/nanoclaw · error · Error

bad request shape

Error message

bad request shape

What it means

The ncl Unix-socket server parses each newline-delimited frame as JSON and requires it to match the RequestFrame shape; malformed JSON or a wrong shape yields this error reply (wrapped from JSON.parse or the isRequestFrame guard).

Source

Thrown at src/cli/socket-server.ts:76

    buffer += chunk.toString('utf8');
    let idx: number;
    while ((idx = buffer.indexOf('\n')) >= 0) {
      const line = buffer.slice(0, idx).trim();
      buffer = buffer.slice(idx + 1);
      if (!line) continue;
      void handleFrame(conn, line);
    }
  });
  conn.on('error', (err) => {
    log.warn('ncl CLI server connection error', { err });
  });
}

async function handleFrame(conn: net.Socket, line: string): Promise<void> {
  let req: RequestFrame;
  try {
    const parsed: unknown = JSON.parse(line);
    if (!isRequestFrame(parsed)) throw new Error('bad request shape');
    req = parsed;
  } catch (e) {
    write(conn, {
      id: 'unknown',
      ok: false,
      error: {
        code: 'transport-error',
        message: `bad frame: ${e instanceof Error ? e.message : String(e)}`,
      },
    });
    return;
  }

  // Host caller — connecting to data/ncl.sock requires file-system access
  // to a 0600 socket owned by the host user, so we treat the socket path
  // itself as the auth boundary.
  const ctx: CallerContext = { caller: 'host' };
  const res = await dispatch(req, ctx);

View on GitHub (pinned to 294ef2aee8)

Solutions

  1. Send valid JSON matching the RequestFrame shape the server expects
  2. Use the provided ncl client / socket transport instead of hand-rolled frames
  3. If a version mismatch, restart the socket server and use the matching ncl build

Example fix

# before
echo 'wirings list' | nc -U /path/to/socket
# after (one JSON request frame per line)
echo '{"id":"1","command":"wirings","verb":"list","args":{}}' | nc -U /path/to/socket
Defensive patterns

Strategy: type-guard

Validate before calling

const line = JSON.stringify({ id: '1', command: 'groups', verb: 'list', args: {} });

Type guard

function isRequestFrame(x: unknown): x is RequestFrame {
  return typeof x === 'object' && x !== null && 'id' in x && 'command' in x;
}

Try / catch

try { await handleFrame(conn, line); } catch { write(conn, { id: 'unknown', ok: false, error: { message: 'bad request shape' } }); }

Prevention

When it happens

Trigger: Sending a non-JSON line, or a JSON value missing required RequestFrame fields (id, command structure), to the ncl socket.

Common situations: Custom scripts speaking the socket protocol by hand, version skew between client and server frame format, or debugging with netcat and forgetting quotes.

Related errors


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