{"id":"bbd61047a1d6ae9c","repo":"drizzle-team/drizzle-orm","slug":"streaming-is-not-supported-by-the-planetscale-serv","errorCode":null,"errorMessage":"Streaming is not supported by the PlanetScale Serverless driver","messagePattern":"Streaming is not supported by the PlanetScale Serverless driver","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"drizzle-orm/src/planetscale-serverless/session.ts","lineNumber":109,"sourceCode":"\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t\treturn returningResponse;\n\t\t\t}\n\t\t\treturn res;\n\t\t}\n\t\tconst { rows } = await this.queryWithCache(queryString, params, async () => {\n\t\t\treturn await client.execute(queryString, params, query);\n\t\t});\n\n\t\tif (customResultMapper) {\n\t\t\treturn customResultMapper(rows as unknown[][]);\n\t\t}\n\n\t\treturn rows.map((row) => mapResultRow<T['execute']>(fields!, row as unknown[], joinsNotNullableMap));\n\t}\n\n\toverride iterator(_placeholderValues?: Record<string, unknown>): AsyncGenerator<T['iterator']> {\n\t\tthrow new Error('Streaming is not supported by the PlanetScale Serverless driver');\n\t}\n}\n\nexport interface PlanetscaleSessionOptions {\n\tlogger?: Logger;\n\tcache?: Cache;\n}\n\nexport class PlanetscaleSession<\n\tTFullSchema extends Record<string, unknown>,\n\tTSchema extends TablesRelationalConfig,\n> extends MySqlSession<MySqlQueryResultHKT, PlanetScalePreparedQueryHKT, TFullSchema, TSchema> {\n\tstatic override readonly [entityKind]: string = 'PlanetscaleSession';\n\n\tprivate logger: Logger;\n\tprivate client: Client | Transaction | Connection;\n\tprivate cache: Cache;\n","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/drizzle-team/drizzle-orm/blob/b7862528fd8fc39bc2653a6c18dad7c1f4e68d10/drizzle-orm/src/planetscale-serverless/session.ts#L91-L127","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use .all()/.execute() and process the returned array in chunks in application code; PlanetScale serverless returns the full result set.","Add LIMIT/OFFSET or keyset pagination to bound result size rather than relying on streaming.","If true streaming is required, switch to a driver that supports cursors (mysql2 over a TCP connection)."],"exampleFix":"// before (throws)\nconst stmt = db.select().from(users).prepare();\nfor await (const row of stmt.iterator()) { /* ... */ }\n\n// after\nconst rows = await db.select().from(users).all();\nfor (const row of rows) { /* ... */ }","handlingStrategy":"validation","validationCode":"// Do not call iterator() on PlanetScale-serverless prepared queries.\nimport { entityKind } from 'drizzle-orm/entity';\n\nfunction supportsIterator(db: any): boolean {\n  const sessionKind = db?.session?.[entityKind];\n  return sessionKind !== 'PlanetscaleSession';\n}\n\nconst result = supportsIterator(db)\n  ? (async () => { for await (const r of stmt.iterator()) yield r; })()\n  : await stmt.all();","typeGuard":"function isPlanetScaleServerless(db: any): boolean {\n  return db?.session?.[Symbol.for('drizzle:entityKind')] === 'PlanetscaleSession';\n}","tryCatchPattern":"try {\n  for await (const row of stmt.iterator()) { /* ... */ }\n} catch (e) {\n  if (e instanceof Error && /Streaming is not supported by the PlanetScale Serverless driver/.test(e.message)) {\n    const rows = await stmt.all();\n    for (const row of rows) { /* ... */ }\n  } else throw e;\n}","preventionTips":["Avoid .iterator() in shared code paths; use .all() for cross-driver compatibility.","Paginate large result sets explicitly with LIMIT/OFFSET or keyset pagination.","Encapsulate result-set access behind a function so the streaming/non-streaming choice is centralized."],"tags":["planetscale","serverless","streaming","cursor","not-supported"],"analyzedSha":"b7862528fd8fc39bc2653a6c18dad7c1f4e68d10","analyzedAt":"2026-08-03T18:11:14.318Z","schemaVersion":2}