{"record":{"id":"bf328b79fbb65c62","repo":"vercel/ai","slug":"append-the-value-is-not-a-string-received","errorCode":null,"errorMessage":".append(): The value is not a string. Received: ${typeof value}","messagePattern":"\\.append\\(\\): The value is not a string\\. Received: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/rsc/src/streamable-value/create-streamable-value.ts","lineNumber":234,"sourceCode":"      resolvePrevious(createWrapped());\n\n      warnUnclosedStream();\n\n      return streamable;\n    },\n    append(value: T) {\n      assertStream('.append()');\n\n      if (\n        typeof currentValue !== 'string' &&\n        typeof currentValue !== 'undefined'\n      ) {\n        throw new Error(\n          `.append(): The current value is not a string. Received: ${typeof currentValue}`,\n        );\n      }\n      if (typeof value !== 'string') {\n        throw new Error(\n          `.append(): The value is not a string. Received: ${typeof value}`,\n        );\n      }\n\n      const resolvePrevious = resolvable.resolve;\n      resolvable = createResolvablePromise();\n\n      if (typeof currentValue === 'string') {\n        currentPatchValue = [0, value];\n        (currentValue as string) = currentValue + value;\n      } else {\n        currentPatchValue = undefined;\n        currentValue = value;\n      }\n\n      currentPromise = resolvable.promise;\n      resolvePrevious(createWrapped());\n","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/rsc/src/streamable-value/create-streamable-value.ts#L216-L252","documentation":"append() validates its argument must be a string since it streams incremental text chunks. Passing a non-string value (number, object, etc.) throws this error reporting the received typeof.","triggerScenarios":"Calling streamable.append(123), .append(someObject), .append(null), or .append(undefined) on a streamable value.","commonSituations":"Passing non-string LLM token deltas (e.g. parsed objects) to append; assuming append accepts arbitrary values like update does; TS types bypassed with any or untyped data from an API.","solutions":["Coerce the chunk to a string before appending (String(chunk) or chunk.toString())","Use update() if you need to set non-string values","Add runtime validation on streamed data before appending","Fix TypeScript types so append is only called with string values"],"exampleFix":"// before\nstreamable.append(chunk); // chunk: unknown\n// after\nif (typeof chunk === 'string') streamable.append(chunk);","handlingStrategy":"validation","validationCode":"function appendText(streamable, chunk) {\n  if (typeof chunk !== 'string') {\n    throw new TypeError('append expects string chunks, got: ' + typeof chunk);\n  }\n  streamable.append(chunk);\n}","typeGuard":"function isStringChunk(chunk) {\n  return typeof chunk === 'string';\n}","tryCatchPattern":"try {\n  streamable.append(chunk);\n} catch (e) {\n  if (!/The value is not a string/.test(String(e.message))) throw e;\n  streamable.append(String(chunk));\n}","preventionTips":["Type stream inputs as string and enable strict TypeScript to catch this at compile time","Coerce provider deltas (e.g. String(delta)) before appending","Add a unit test asserting append rejects non-string chunks"],"tags":["streaming","rsc","type-error","append"],"backgroundTag":"invalid-stream-value-type","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}