drizzle-team/drizzle-orm · error · Error

Streaming is not supported by the PlanetScale Serverless…

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.

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: /api/errors/bbd61047a1d6ae9c. Report an issue: GitHub.

Appendix: 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)