vercel/ai · error

Invalid value: this hook only accepts values created via `cr

Error message

Invalid value: this hook only accepts values created via `createStreamableValue`.

What it means

readStreamableValue only accepts objects produced by createStreamableValue; it detects the internal StreamableValue signature via isStreamableValue and throws otherwise. This prevents consuming arbitrary objects as streams and gives a clear message instead of confusing runtime failures later.

Source

Thrown at packages/rsc/src/streamable-value/read-streamable-value.tsx:38

 * }
 * ```
 *
 * And to read the value:
 *
 * ```js
 * const streamableValue = await action()
 * for await (const v of readStreamableValue(streamableValue)) {
 *   console.log(v)
 * }
 * ```
 *
 * This logs out 1, 2, 3 on console.
 */
export function readStreamableValue<T = unknown>(
  streamableValue: StreamableValue<T>,
): AsyncIterable<T | undefined> {
  if (!isStreamableValue(streamableValue)) {
    throw new Error(
      'Invalid value: this hook only accepts values created via `createStreamableValue`.',
    );
  }

  return {
    [Symbol.asyncIterator]() {
      let row: StreamableValue<T> | Promise<StreamableValue<T>> =
        streamableValue;
      let value = row.curr; // the current value
      let isDone = false;
      let isFirstIteration = true;

      return {
        async next() {
          // the iteration is done already, return the last value:
          if (isDone) return { value, done: true };

          // resolve the promise at the beginning of each iteration:

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Pass only values returned from createStreamableValue().value
  2. Verify you are not passing a createStreamableUI result where a streamable value is expected
  3. Check for AI SDK version mismatches between server code creating the value and client code reading it

Example fix

// before
const [value] = useState(42);
readStreamableValue(value); // throws
// after
const streamable = createStreamableValue(42);
readStreamableValue(streamable.value);
Defensive patterns

Strategy: type-guard

Validate before calling

import { isStreamableValue } from 'ai/rsc';
if (!isStreamableValue(maybeValue)) throw new TypeError('expected createStreamableValue().value');

Type guard

function isStreamableValueLike(v: unknown): v is StreamableValue {
  return typeof v === 'object' && v !== null && 'type' in v && 'curr' in v;
}

Try / catch

try {
  for await (const v of readStreamableValue(input)) { /* ... */ }
} catch (e) {
  if (e instanceof Error && e.message.includes('createStreamableValue')) {
    console.error('Not a streamable value:', input);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a plain object, a Promise, a string, or an object created by a different library version to readStreamableValue; passing a value from createStreamableUI (UI chunk) instead of createStreamableValue; reading a deserialized value that lost the internal signature.

Common situations: Mixing value streams with UI streams; TypeScript types erased or value JSON-serialized across a boundary, dropping the marker; version mismatch between the package that created the value and the one consuming it.

Related errors


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