vercel/ai · error · Error

.append(): The current value is not a string. Received: ${ty

Error message

.append(): The current value is not a string. Received: ${typeof currentValue}

What it means

append() only works on streamable values whose current value is a string (or undefined for a fresh value). If the value has been set to any other type via update() or the initial value, this error is thrown, reporting the actual typeof the current value.

Source

Thrown at packages/rsc/src/streamable-value/create-streamable-value.ts:229

      const resolvePrevious = resolvable.resolve;
      resolvable = createResolvablePromise();

      updateValueStates(value);
      currentPromise = resolvable.promise;
      resolvePrevious(createWrapped());

      warnUnclosedStream();

      return streamable;
    },
    append(value: T) {
      assertStream('.append()');

      if (
        typeof currentValue !== 'string' &&
        typeof currentValue !== 'undefined'
      ) {
        throw new Error(
          `.append(): The current value is not a string. Received: ${typeof currentValue}`,
        );
      }
      if (typeof value !== 'string') {
        throw new Error(
          `.append(): The value is not a string. Received: ${typeof value}`,
        );
      }

      const resolvePrevious = resolvable.resolve;
      resolvable = createResolvablePromise();

      if (typeof currentValue === 'string') {
        currentPatchValue = [0, value];
        (currentValue as string) = currentValue + value;
      } else {
        currentPatchValue = undefined;
        currentValue = value;

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Use append() exclusively from the start on a createStreamableValue() with no initial (or a string initial) value
  2. Use update() instead of append() if you intend to replace the value with non-string data
  3. Use separate streamable values: one for streamed text (append), one for structured data (update)
  4. Reset the value to a string with update('') before appending

Example fix

// before
const v = createStreamableValue({ count: 0 });
v.append('hi'); // throws
// after
const v = createStreamableValue('');
v.append('hi');
Defensive patterns

Strategy: validation

Validate before calling

function safeAppend(streamable, current, chunk) {
  if (typeof current !== 'string' && typeof current !== 'undefined') {
    throw new TypeError('append requires a string-valued streamable, got: ' + typeof current);
  }
  streamable.append(chunk);
}

Type guard

function canAppendTo(value) {
  return typeof value === 'string' || typeof value === 'undefined';
}

Try / catch

try {
  streamable.append(chunk);
} catch (e) {
  if (!/current value is not a string/.test(String(e.message))) throw e;
  streamable.update(String(chunk)); // fall back to replace-mode
}

Prevention

When it happens

Trigger: Creating createStreamableValue({someObject}) or calling .update({...}) / .update(42), then calling .append('text') — the current value is no longer a string.

Common situations: Mixing text-streaming append() with whole-value update() on the same streamable; initializing a streamable with a non-string value intending to append to it later.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/92fd374d975c8435. Report an issue: GitHub.