drizzle-team/drizzle-orm · error · Error

Streaming is not supported by the PlanetScale Serverless dri

Error message

Streaming is not supported by the PlanetScale Serverless driver

What it means

PlanetscalePreparedQuery.iterator() throws because the PlanetScale serverless driver (@planetscale/database) executes whole queries over HTTP and does not expose a server-side cursor/stream. Drizzle's iterator() override fails fast to make the limitation explicit rather than buffering silently.

Source

Thrown at drizzle-orm/src/planetscale-serverless/session.ts:109

					j++;
				}
				return returningResponse;
			}
			return res;
		}
		const { rows } = await this.queryWithCache(queryString, params, async () => {
			return await client.execute(queryString, params, query);
		});

		if (customResultMapper) {
			return customResultMapper(rows as unknown[][]);
		}

		return rows.map((row) => mapResultRow<T['execute']>(fields!, row as unknown[], joinsNotNullableMap));
	}

	override iterator(_placeholderValues?: Record<string, unknown>): AsyncGenerator<T['iterator']> {
		throw new Error('Streaming is not supported by the PlanetScale Serverless driver');
	}
}

export interface PlanetscaleSessionOptions {
	logger?: Logger;
	cache?: Cache;
}

export class PlanetscaleSession<
	TFullSchema extends Record<string, unknown>,
	TSchema extends TablesRelationalConfig,
> extends MySqlSession<MySqlQueryResultHKT, PlanetScalePreparedQueryHKT, TFullSchema, TSchema> {
	static override readonly [entityKind]: string = 'PlanetscaleSession';

	private logger: Logger;
	private client: Client | Transaction | Connection;
	private cache: Cache;

View on GitHub (pinned to b7862528fd)

Solutions

  1. Use .all()/.execute() and process the returned array in chunks in application code; PlanetScale serverless returns the full result set.
  2. Add LIMIT/OFFSET or keyset pagination to bound result size rather than relying on streaming.
  3. If true streaming is required, switch to a driver that supports cursors (mysql2 over a TCP connection).

Example fix

// before (throws)
const stmt = db.select().from(users).prepare();
for await (const row of stmt.iterator()) { /* ... */ }

// after
const rows = await db.select().from(users).all();
for (const row of rows) { /* ... */ }
Defensive patterns

Strategy: validation

Validate before calling

// Do not call iterator() on PlanetScale-serverless prepared queries.
import { entityKind } from 'drizzle-orm/entity';

function supportsIterator(db: any): boolean {
  const sessionKind = db?.session?.[entityKind];
  return sessionKind !== 'PlanetscaleSession';
}

const result = supportsIterator(db)
  ? (async () => { for await (const r of stmt.iterator()) yield r; })()
  : await stmt.all();

Type guard

function isPlanetScaleServerless(db: any): boolean {
  return db?.session?.[Symbol.for('drizzle:entityKind')] === 'PlanetscaleSession';
}

Try / catch

try {
  for await (const row of stmt.iterator()) { /* ... */ }
} catch (e) {
  if (e instanceof Error && /Streaming is not supported by the PlanetScale Serverless driver/.test(e.message)) {
    const rows = await stmt.all();
    for (const row of rows) { /* ... */ }
  } else throw e;
}

Prevention

When it happens

Trigger: Calling .iterator() on a prepared query or a select built from a PlanetScale-serverless Drizzle database, e.g. for await (const row of db.select().from(t).prepare().iterator()) {}. Also any cursor-based pagination helper that calls iterator() under the hood.

Common situations: Porting code from mysql2 streaming cursors to PlanetScale serverless. Large-result-set processing where a developer reaches for streaming to control memory, not realizing the HTTP driver returns the full set.

Related errors


AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03). Data as JSON: /data/errors/bbd61047a1d6ae9c.json. Report an issue: GitHub.