{"record":{"id":"013086162ee2e556","repo":"windmill-labs/windmill","slug":"26000","errorCode":"26000","errorMessage":"prepared statement ${formatProtocolName(bind.statementName, \"statement\")} does not exist","messagePattern":"prepared statement (.+?) does not exist","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/commands/datatable/serve.ts","lineNumber":441,"sourceCode":"  preparedStatements.set(parse.statementName, {\n    query: parse.query,\n    parameterTypeOids: parse.parameterTypeOids,\n  });\n  if (parse.statementName === \"\") {\n    portals.delete(\"\");\n  }\n  return buildParseComplete();\n}\n\nfunction handleBindMessage(\n  data: Uint8Array,\n  preparedStatements: Map<string, PreparedStatementState>,\n  portals: Map<string, PortalState>,\n): Uint8Array {\n  const bind = readBindMessage(data);\n  const statement = preparedStatements.get(bind.statementName);\n  if (!statement) {\n    throw createPgProtocolError(\n      `prepared statement ${formatProtocolName(bind.statementName, \"statement\")} does not exist`,\n      \"26000\",\n    );\n  }\n  for (let i = 0; i < bind.parameters.length; i += 1) {\n    if (bind.parameters[i] !== null && resolveParameterFormatCode(bind.parameterFormatCodes, i) !== 0) {\n      throw createPgProtocolError(\n        \"binary parameter formats are not supported by 'wmill datatable serve'\",\n        \"0A000\",\n      );\n    }\n  }\n  if (bind.resultFormatCodes.some((code) => code !== 0)) {\n    throw createPgProtocolError(\n      \"binary result formats are not supported by 'wmill datatable serve'\",\n      \"0A000\",\n    );\n  }","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/commands/datatable/serve.ts#L423-L459","documentation":"In `wmill datatable serve`, a Bind (B) message referenced a statement name that is not present in the connection's `preparedStatements` map, so `handleBindMessage` throws SQLSTATE `26000` (invalid_sql_statement_name). Per the Postgres protocol, a Bind must target a statement created earlier by a Parse on the same connection.","triggerScenarios":"The client sends Bind for a named statement that was never Parsed, was already closed via a Close (C) message, or belonged to a different connection/session; also happens after a server error discarded prepared statements while the driver's local cache still thinks they exist.","commonSituations":"Connection pooling/multiplexing where the driver reuses a statement name across recycled connections; a prior error mid-transaction cleared server-side state but the client kept its prepared-statement cache; driver retry logic replaying Bind without re-Parsing after a disconnect.","solutions":["Reconnect or reset the connection so the driver's prepared-statement cache and the server state resynchronize (the driver will re-Parse on a fresh session).","Disable prepared statements in the client driver if supported (e.g. `prepared_statements=false` in the Postgres DSN, or `preferPreparedStatements: false`) so Binds always reference the unnamed statement.","Upgrade `wmill` / the datatable server — a bug where statements were dropped prematurely would be fixed in a newer release.","In application code, catch SQLSTATE 26000 and retry the query after re-preparing, the standard Postgres recovery for invalid_sql_statement_name."],"exampleFix":"// before\npostgres://user:pw@host/db  // pool reuses cached statement names across connections\n// after\npostgres://user:pw@host/db?prepared_statements=false","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function safeQuery(client, sql, params) {\n  try {\n    return await client.query(sql, params);\n  } catch (err) {\n    if (err.code === '26000') {\n      return await client.query({ text: sql, values: params, name: undefined }); // re-issue unnamed\n    }\n    throw err;\n  }\n}","preventionTips":["Catch SQLSTATE 26000 and re-prepare/retry, the standard Postgres recovery.","Disable client-side prepared statements when connecting through pooling layers or emulators.","Avoid reusing prepared statement names across pooled/recycled connections.","After any server error, assume server-side statement state is gone and re-Parse before Bind."],"tags":["postgres","wire-protocol","prepared-statements","datatable","cli"],"backgroundTag":"invalid-sql-statement-name","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}