{"record":{"id":"6550d68fd092546e","repo":"nanocoai/nanoclaw","slug":"bad-request-shape","errorCode":null,"errorMessage":"bad request shape","messagePattern":"bad request shape","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/socket-server.ts","lineNumber":76,"sourceCode":"    buffer += chunk.toString('utf8');\n    let idx: number;\n    while ((idx = buffer.indexOf('\\n')) >= 0) {\n      const line = buffer.slice(0, idx).trim();\n      buffer = buffer.slice(idx + 1);\n      if (!line) continue;\n      void handleFrame(conn, line);\n    }\n  });\n  conn.on('error', (err) => {\n    log.warn('ncl CLI server connection error', { err });\n  });\n}\n\nasync function handleFrame(conn: net.Socket, line: string): Promise<void> {\n  let req: RequestFrame;\n  try {\n    const parsed: unknown = JSON.parse(line);\n    if (!isRequestFrame(parsed)) throw new Error('bad request shape');\n    req = parsed;\n  } catch (e) {\n    write(conn, {\n      id: 'unknown',\n      ok: false,\n      error: {\n        code: 'transport-error',\n        message: `bad frame: ${e instanceof Error ? e.message : String(e)}`,\n      },\n    });\n    return;\n  }\n\n  // Host caller — connecting to data/ncl.sock requires file-system access\n  // to a 0600 socket owned by the host user, so we treat the socket path\n  // itself as the auth boundary.\n  const ctx: CallerContext = { caller: 'host' };\n  const res = await dispatch(req, ctx);","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/cli/socket-server.ts#L58-L94","documentation":"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).","triggerScenarios":"Sending a non-JSON line, or a JSON value missing required RequestFrame fields (id, command structure), to the ncl socket.","commonSituations":"Custom scripts speaking the socket protocol by hand, version skew between client and server frame format, or debugging with netcat and forgetting quotes.","solutions":["Send valid JSON matching the RequestFrame shape the server expects","Use the provided ncl client / socket transport instead of hand-rolled frames","If a version mismatch, restart the socket server and use the matching ncl build"],"exampleFix":"# before\necho 'wirings list' | nc -U /path/to/socket\n# after (one JSON request frame per line)\necho '{\"id\":\"1\",\"command\":\"wirings\",\"verb\":\"list\",\"args\":{}}' | nc -U /path/to/socket","handlingStrategy":"type-guard","validationCode":"const line = JSON.stringify({ id: '1', command: 'groups', verb: 'list', args: {} });","typeGuard":"function isRequestFrame(x: unknown): x is RequestFrame {\n  return typeof x === 'object' && x !== null && 'id' in x && 'command' in x;\n}","tryCatchPattern":"try { await handleFrame(conn, line); } catch { write(conn, { id: 'unknown', ok: false, error: { message: 'bad request shape' } }); }","preventionTips":["Always use the shipped ncl client over the raw socket","One JSON frame per line; validate before sending"],"tags":["cli","socket","json","protocol-validation"],"backgroundTag":"invalid-request-payload","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}