windmill-labs/windmill · error
34000
34000
Error message
portal ${formatProtocolName(describe.name, "portal")} does not exist What it means
PostgreSQL 'invalid_cursor_name' (34000) error: a Describe message targeting type 'P' (portal) referenced a portal name not present in the portals map. Portals are created by Bind and live only on the current connection, so describing an unknown portal is a protocol-level error.
Source
Thrown at cli/src/commands/datatable/serve.ts:506
isQueryLikelySafeToDescribe(statement.query)
) {
const envelope = await executeQuery(statement.query);
return concat([
buildParameterDescription(statement.parameterTypeOids),
envelope.columns.length > 0
? buildRowDescription(envelope.columns)
: buildNoData(),
]);
}
return concat([
buildParameterDescription(statement.parameterTypeOids),
buildNoData(),
]);
}
const portal = portals.get(describe.name);
if (!portal) {
throw createPgProtocolError(
`portal ${formatProtocolName(describe.name, "portal")} does not exist`,
"34000",
);
}
if (!portal.envelope && isQueryLikelySafeToDescribe(portal.query)) {
portal.envelope = await executeQuery(buildPortalQuery(portal));
}
if (portal.envelope?.columns.length) {
portal.sentRowDescription = true;
return buildRowDescription(portal.envelope.columns);
}
return buildNoData();
}
async function handleExecuteMessage(
data: Uint8Array,
portals: Map<string, PortalState>,View on GitHub (pinned to e474e8803c)
Solutions
- Ensure a Bind for the portal name is executed (and succeeded) before Describe(P). Check logs for a prior Bind error.
- Keep the Parse→Bind→Describe→Execute sequence on one connection without reconnects; disable pooling or statement reuse that spans connections.
- If streaming with cursors, re-open the portal (re-Bind) once results are exhausted instead of describing a completed portal.
Defensive patterns
Strategy: retry
Try / catch
try {
await describePortal(portalName);
} catch (e) {
if (e.code === '34000' || /portal .* does not exist/.test(e.message)) {
// re-run Bind to recreate the portal, then retry Describe
} else throw e;
} Prevention
- Bind before every Describe(P)/Execute; treat portals as single-use.
- Keep the whole Parse→Bind→Describe→Execute sequence on one connection.
- Investigate any earlier Bind failure (e.g. binary format) that prevented portal creation.
When it happens
Trigger: Client sends Describe(P, name) before any Bind created that portal, after the portal completed (portal state is cleared/rowOffset reset on completion), or after a connection reset cleared the portals map.
Common situations: Driver-side connection failover between Bind and Describe; cursor-style streaming clients that expect portals to persist across transactions; a failed earlier Bind (e.g. binary-format rejection from errors 1280/1281) meant the portal was never created.
Related errors
- 0A000
- 26000
- ${extractErrorMessage(result)}
- App ${appPath} not found
- Dependency generation failed: ${queueResponse.status} ${queu
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/cc42742e5b166beb.
Report an issue: GitHub.