{"record":{"id":"ff3b11dee8e3050c","repo":"CopilotKit/CopilotKit","slug":"whatsapp-control-value-too-large-to-round-trip-en","errorCode":null,"errorMessage":"WhatsApp control value too large to round-trip: encoded id is ${encoded.length} chars (max ${WA_LIMITS.controlId}). Use a smaller value or a short key the handler maps.","messagePattern":"WhatsApp control value too large to round-trip: encoded id is (.+?) chars \\(max (.+?)\\)\\. Use a smaller value or a short key the handler maps\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/channels-whatsapp/src/render/message.ts","lineNumber":269,"sourceCode":"  if (handler && typeof handler === \"object\" && \"id\" in handler) {\n    const id = (handler as { id?: unknown }).id;\n    if (typeof id === \"string\") return id;\n  }\n  return undefined;\n}\n\n/**\n * Build a reply-control id. A bare minted id is short and safe to clamp. When a\n * value must round-trip (WhatsApp replies carry only an id, no value field) we\n * encode `${id}::${JSON.stringify(value)}`; if that exceeds WhatsApp's 256-char\n * id limit it CANNOT round-trip, so we fail loudly rather than truncate (which\n * would make decodeInteraction silently parse garbage).\n */\nfunction buildControlId(actionId: string, value: unknown): string {\n  if (value === undefined) return truncateText(actionId, WA_LIMITS.controlId);\n  const encoded = `${actionId}::${JSON.stringify(value)}`;\n  if (encoded.length > WA_LIMITS.controlId) {\n    throw new Error(\n      `WhatsApp control value too large to round-trip: encoded id is ${encoded.length} chars ` +\n        `(max ${WA_LIMITS.controlId}). Use a smaller value or a short key the handler maps.`,\n    );\n  }\n  return encoded;\n}\n\n/**\n * Flatten a `BotChildren` tree to a single text string. Handles both plain\n * string children and `renderToIR`-lowered `{ type: \"text\", props: { value } }`\n * leaf nodes.\n */\nfunction textOf(children: unknown): string {\n  if (children == null || children === false || children === true) return \"\";\n  if (typeof children === \"string\") return children;\n  if (typeof children === \"number\") return String(children);\n  if (Array.isArray(children)) return children.map(textOf).join(\"\");\n  const node = children as ChannelNode;","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/CopilotKit/CopilotKit/blob/68fbe97d87420bd84e8196965c71bd6e394a3f7a/packages/channels-whatsapp/src/render/message.ts#L251-L287","documentation":"WhatsApp interactive buttons/rows carry the action id in a payload with a hard character limit (WA_LIMITS.controlId). CopilotKit encodes `actionId::JSON.stringify(value)` into that field; when the encoded string exceeds the limit the renderer refuses to emit a message that could never round-trip back through decodeInteraction.","triggerScenarios":"Rendering a control (list item, button, etc.) with a large `value` prop — e.g. a whole object, long string, or base64 blob — so actionId+JSON exceeds the limit.","commonSituations":"Passing full row data (records, URLs, base64 images) as the value instead of a key; generating dynamic values that grow unbounded.","solutions":["Pass a short key (id/index) as value and map it back to the full data inside your handler","Pre-serialize/truncate large values and store them server-side, sending only an id","If value is undefined, only actionId is used — prefer omitting value entirely"],"exampleFix":"// before\n{ type: \"list\", value: bigProductObject }\n\n// after\n{ type: \"list\", value: bigProductObject.sku } // handler looks up by sku","handlingStrategy":"validation","validationCode":"const encoded = `${actionId}::${JSON.stringify(value)}`;\nif (encoded.length > 256 /* conservative stand-in for WA_LIMITS.controlId */) value = shortKeyFor(value);","typeGuard":"function isControlValueSafe(actionId: string, value: unknown): boolean {\n  return value === undefined || `${actionId}::${JSON.stringify(value)}`.length <= 200;\n}","tryCatchPattern":"null","preventionTips":["Pass short ids/keys as values, look up full data in the handler","Never put base64 or long strings in control values","Add a unit test asserting encoded lengths stay under the limit"],"tags":["whatsapp","payload-limit","render","control-id"],"backgroundTag":"payload-too-large","analyzedSha":"68fbe97d87420bd84e8196965c71bd6e394a3f7a","analyzedAt":"2026-08-27T04:03:26.537Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}