vercel/ai · error

Chunking function must return a non-empty string.

Error message

Chunking function must return a non-empty string.

What it means

Plain Error thrown by smoothStream when a custom ChunkDetector function returns an empty string ('' or zero-length match). A chunker must either return null (nothing to flush yet) or a non-empty prefix of the buffer; an empty return is treated as a programming bug in the detector.

Source

Thrown at packages/ai/src/generate-text/smooth-stream.ts:71

    typeof chunking.segment === 'function'
  ) {
    const segmenter = chunking as Intl.Segmenter;
    detectChunk = (buffer: string) => {
      if (buffer.length === 0) return null;
      const iterator = segmenter.segment(buffer)[Symbol.iterator]();
      const first = iterator.next().value;
      return first?.segment || null;
    };
  } else if (typeof chunking === 'function') {
    detectChunk = buffer => {
      const match = chunking(buffer);

      if (match == null) {
        return null;
      }

      if (!match.length) {
        throw new Error(`Chunking function must return a non-empty string.`);
      }

      if (!buffer.startsWith(match)) {
        throw new Error(
          `Chunking function must return a match that is a prefix of the buffer. Received: "${match}" expected to start with "${buffer}"`,
        );
      }

      return match;
    };
  } else {
    const chunkingRegex =
      typeof chunking === 'string'
        ? CHUNKING_REGEXPS[chunking]
        : chunking instanceof RegExp
          ? chunking
          : undefined;

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Return `null` instead of an empty string when no chunk should be emitted yet.
  2. Check the detector for paths that can compute a zero-length slice; guard with `if (idx <= 0) return null;`.
  3. Test the detector against edge inputs: '', ' ', first partial token, multi-byte characters.

Example fix

// before
const chunking = (buffer: string) => buffer.slice(0, buffer.indexOf(' ') + 1); // '' when no space
// after
const chunking = (buffer: string) => {
  const idx = buffer.indexOf(' ');
  return idx === -1 || idx + 1 === 0 ? null : buffer.slice(0, idx + 1);
};
Defensive patterns

Strategy: validation

Validate before calling

const detector = (buffer: string) => {
  const chunk = computeChunk(buffer);
  if (chunk != null && chunk.length === 0) return null; // never return ''
  return chunk;
};

Type guard

function isValidDetectorResult(r: string | null): r is string {
  return r === null || r.length > 0;
}

Try / catch

try {
  result.textStream.pipeThrough(smoothStream({ chunking: detector }).pipeThrough(new TextEncoderStream()));
} catch (e) {
  if (e instanceof Error && e.message.includes('non-empty string')) {
    // fall back to default word chunking
  } else throw e;
}

Prevention

When it happens

Trigger: Passing `chunking: (buffer) => ...` that returns '' — e.g. slicing with an index computed as 0, regex with optional capture yielding empty, or returning `match?.[0] ?? ''` instead of null.

Common situations: Custom detectors written with `buffer.slice(0, n)` where n=0 on first token; using `match[1]` from a regex whose capture group didn't participate; returning empty on whitespace-only buffers.

Related errors


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