eyaltoledano/claude-task-master · error · StreamingError

STREAM_NOT_ITERABLE

STREAM_NOT_ITERABLE

Error message

Stream object is not iterable - no textStream, fullStream, or direct async iterator found

What it means

detectStreamType inspects the stream object for a textStream, a fullStream, or a direct async iterator; if none is found it throws this StreamingError with code STREAM_NOT_ITERABLE. It means the value passed to the parser cannot be consumed by any supported streaming strategy.

Source

Thrown at src/utils/stream-parser.js:171

	}

	detectStreamType(textStream) {
		// Check for textStream property
		if (this.hasAsyncIterator(textStream?.textStream)) {
			return (stream) => this.processTextStream(stream.textStream);
		}

		// Check for fullStream property
		if (this.hasAsyncIterator(textStream?.fullStream)) {
			return (stream) => this.processFullStream(stream.fullStream);
		}

		// Check if stream itself is iterable
		if (this.hasAsyncIterator(textStream)) {
			return (stream) => this.processDirectStream(stream);
		}

		throw new StreamingError(
			'Stream object is not iterable - no textStream, fullStream, or direct async iterator found',
			STREAMING_ERROR_CODES.STREAM_NOT_ITERABLE
		);
	}

	hasAsyncIterator(obj) {
		return obj && typeof obj[Symbol.asyncIterator] === 'function';
	}

	async processTextStream(stream) {
		for await (const chunk of stream) {
			this.onChunk(chunk);
		}
	}

	async processFullStream(stream) {
		for await (const chunk of stream) {
			if (chunk.type === 'text-delta' && chunk.textDelta) {

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Await the call that produces the stream before passing it: await client.stream(...).
  2. Pass the correct inner stream: result.textStream or result.fullStream instead of the wrapper object.
  3. Verify the object has Symbol.asyncIterator: console.log(typeof stream[Symbol.asyncIterator]).
  4. Log Object.keys(stream) to find the right stream property for your SDK version.

Example fix

// before
const parser = new StreamParser({ jsonPaths: ['$.items'] });
parser.parseStream(client.chat.completions.create({ stream: true }))
// after
const result = await client.chat.completions.create({ stream: true });
parser.parseStream(result.textStream)
Defensive patterns

Strategy: type-guard

Validate before calling

function assertIterableStream(stream) {
  if (
    !stream ||
    (typeof stream[Symbol.asyncIterator] !== 'function' &&
      typeof stream.textStream?.[Symbol.asyncIterator] !== 'function' &&
      typeof stream.fullStream?.[Symbol.asyncIterator] !== 'function')
  ) {
    throw new TypeError('Provided value is not a consumable stream (no textStream/fullStream/asyncIterator)');
  }
  return stream;
}
parser.parseStream(assertIterableStream(maybeStream));

Type guard

function isConsumableStream(v) {
  return Boolean(
    v &&
    (typeof v[Symbol.asyncIterator] === 'function' ||
      (v.textStream && typeof v.textStream[Symbol.asyncIterator] === 'function') ||
      (v.fullStream && typeof v.fullStream[Symbol.asyncIterator] === 'function'))
  );
}

Try / catch

try {
  await parser.parseStream(result);
} catch (err) {
  if (err.code === 'STREAM_NOT_ITERABLE') {
    const inner = result?.textStream ?? result?.fullStream ?? result;
    return parser.parseStream(inner);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling parseStream()/streamHandler with a plain object (e.g. an SDK result wrapper needing .textStream), a Promise that was not awaited, a string, or a stream from an incompatible SDK version where the iterator lives under a different property.

Common situations: Forgetting to await an async factory returning the stream; upgrading an AI SDK and property names changing; passing a Response object instead of its body reader; passing a Node Readable that lacks Symbol.asyncIterator (older polyfills).

Related errors


AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29). Data as JSON: /api/errors/28f4afd81ee30520. Report an issue: GitHub.