{"record":{"id":"5f06fd7702e58c59","repo":"can1357/oh-my-pi","slug":"data-must-be-a-string","errorCode":null,"errorMessage":"data must be a string","messagePattern":"data must be a string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/tui/src/debug-server.ts","lineNumber":359,"sourceCode":"\t\t\t\treturn {\n\t\t\t\t\tok: true,\n\t\t\t\t\tcolumns: this.#tui.terminal.columns,\n\t\t\t\t\trows: this.#tui.terminal.rows,\n\t\t\t\t\tpid: process.pid,\n\t\t\t\t\toverlays: this.#tui.overlayStack.length,\n\t\t\t\t\tfocused: focused === null ? null : componentKind(focused),\n\t\t\t\t\talt_screen: paint?.altScreen ?? false,\n\t\t\t\t\tcursor: paint?.cursor ?? { visible: false },\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"keys\": {\n\t\t\t\tif (typeof request.keys !== \"string\") throw new Error(\"keys must be a string\");\n\t\t\t\tconst parsed = parseKeyTokens(request.keys);\n\t\t\t\tfor (const sequence of parsed.sequences) this.#tui.injectDebugInput(sequence);\n\t\t\t\treturn { ok: true, injected: parsed.events };\n\t\t\t}\n\t\t\tcase \"bytes\":\n\t\t\t\tif (typeof request.data !== \"string\") throw new Error(\"data must be a string\");\n\t\t\t\tthis.#tui.injectDebugInput(request.data);\n\t\t\t\treturn { ok: true };\n\t\t\tcase \"paste\":\n\t\t\t\tif (typeof request.text !== \"string\") throw new Error(\"text must be a string\");\n\t\t\t\tthis.#tui.injectDebugInput(`\\x1b[200~${request.text}\\x1b[201~`);\n\t\t\t\treturn { ok: true };\n\t\t\tcase \"mouse\": {\n\t\t\t\tif (typeof request.x !== \"number\" || typeof request.y !== \"number\")\n\t\t\t\t\tthrow new Error(\"mouse x and y must be numbers\");\n\t\t\t\tconst action = request.action === undefined ? \"click\" : request.action;\n\t\t\t\tif (typeof action !== \"string\") throw new Error(\"mouse action must be a string\");\n\t\t\t\tthis.#tui.injectDebugInput(mouseSequence(request.x, request.y, action));\n\t\t\t\treturn { ok: true };\n\t\t\t}\n\t\t\tcase \"quit\":\n\t\t\t\treturn { ok: true };\n\t\t\tdefault:\n\t\t\t\treturn { ok: false, error: `unknown op ${request.op}` };","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/tui/src/debug-server.ts#L341-L377","documentation":"For the debug server's \"bytes\" operation, #dispatch requires request.data to be a string, which is injected verbatim as a raw input sequence into the TUI. If data is missing or not a string, this error is thrown and returned as a failed response. Raw byte payloads must be provided as (escaped) text in JSON.","triggerScenarios":"Sending {\"op\":\"bytes\"} without data; sending data as an object like {\"bytes\":[27,91]}, a number, or a nested object.","commonSituations":"Clients that base64-encode or numeric-encode escape sequences and send the raw buffer instead of a JSON string; forgetting JSON-escaping for control characters like ESC.","solutions":["Set data to a JSON string containing the raw sequence with escapes, e.g. \"\\u001b[A\" for arrow-up","If you have a byte array, decode it to a UTF-8/latin1 string before sending","Use the \"paste\" or \"keys\" ops instead when they match the intent"],"exampleFix":"// before\n{ \"op\": \"bytes\", \"data\": [27, 91, 65] }\n// after\n{ \"op\": \"bytes\", \"data\": \"\\u001b[A\" }","handlingStrategy":"validation","validationCode":"if (typeof request.data !== \"string\")\n  request.data = Buffer.from(request.data as number[]).toString(\"latin1\");","typeGuard":"function hasStringData(r: { op: string; data?: unknown }): r is { op: \"bytes\"; data: string } {\n  return r.op === \"bytes\" && typeof r.data === \"string\";\n}","tryCatchPattern":"try {\n  const res = await send({ op: \"bytes\", data });\n} catch (err) {\n  if (String(err.message) === \"data must be a string\") {\n    data = String.fromCharCode(...(data as number[]));\n  }\n}","preventionTips":["Encode control characters as \\uXXXX escapes in the JSON string","Convert byte arrays to strings before sending; the wire format is JSON text","Prefer the \"keys\" op for named keys and \"paste\" for text instead of raw bytes"],"tags":["validation","types","debug-server"],"backgroundTag":"invalid-request-field-type","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}