{"record":{"id":"83f27e5b317045b7","repo":"apache/shardingsphere","slug":"invalid-statement-handle-d-83f27e","errorCode":null,"errorMessage":"Invalid statement handle: %d","messagePattern":"Invalid statement handle: (.+?)","errorType":"exception","errorClass":"InvalidStatementHandleException","httpStatus":null,"severity":"error","filePath":"proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/execute/FirebirdExecuteStatementCommandExecutor.java","lineNumber":83,"sourceCode":"@RequiredArgsConstructor\npublic final class FirebirdExecuteStatementCommandExecutor implements CommandExecutor {\n    \n    private final FirebirdExecuteStatementPacket packet;\n    \n    private final ConnectionSession connectionSession;\n    \n    private ProxyBackendHandler proxyBackendHandler;\n    \n    @Getter\n    private ResponseType responseType;\n    \n    @Override\n    public Collection<DatabasePacket> execute() throws SQLException {\n        connectionSession.beginPreparedStatementCache(FirebirdStatementResourceCleaner.createPreparedStatementCacheKey(packet.getStatementId()));\n        try {\n            FirebirdServerPreparedStatement preparedStatement = connectionSession.getServerPreparedStatementRegistry().getPreparedStatement(packet.getStatementId());\n            if (null == preparedStatement) {\n                throw new InvalidStatementHandleException(packet.getStatementId());\n            }\n            validateTransactionHandle();\n            ResponseHeader responseHeader = executePreparedStatement(preparedStatement, packet.getParameterValues());\n            if (responseHeader instanceof QueryResponseHeader) {\n                responseType = ResponseType.QUERY;\n                FirebirdFetchStatementCache.getInstance().registerStatement(connectionSession.getConnectionId(), packet.getStatementId(), proxyBackendHandler);\n                connectionSession.getDatabaseConnectionManager().markResourceInUse(proxyBackendHandler);\n            } else {\n                responseType = ResponseType.UPDATE;\n                preparedStatement.setAffectedRows(((UpdateResponseHeader) responseHeader).getUpdateCount());\n            }\n            Collection<DatabasePacket> result = new LinkedList<>();\n            if (packet.isStoredProcedure() && proxyBackendHandler.next()) {\n                result.add(getSQLResponse());\n            }\n            result.add(new FirebirdGenericResponsePacket());\n            return result;\n        } finally {","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/execute/FirebirdExecuteStatementCommandExecutor.java#L65-L101","documentation":"InvalidStatementHandleException thrown by FirebirdExecuteStatementCommandExecutor when the statement handle in an EXECUTE statement packet is absent from the connection's ServerPreparedStatementRegistry. The proxy refuses to execute what was never prepared or was already freed on this session.","triggerScenarios":"execute() begins a prepared-statement cache scope, then getPreparedStatement(packet.getStatementId()) returns null; happens when EXECUTE precedes PREPARE, follows FREE STATEMENT (DROP/UNPREPARE), or uses a handle from a different connection.","commonSituations":"client (or ORM layer) executes a statement id it cached across a reconnect; FREE sent by a cleanup thread races with a pending EXECUTE; raw-protocol client misreads the handle from the prepare response; connection pool handle leakage between sessions.","solutions":["Always PREPARE on the same connection before EXECUTE and take the handle from the prepare response.","After FREE STATEMENT or session-level cleanup, re-prepare instead of reusing old handles.","Never share statement handles across connections from a pool.","Check for races where one thread frees statements while another executes them."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"Integer handle = preparedHandles.get(sql);\nif (handle == null) { handle = sendPrepare(sql).statementHandle; preparedHandles.put(sql, handle); }\nsendExecuteStatement(handle, params);","typeGuard":null,"tryCatchPattern":"catch (SQLException e) {\n    if (e.getMessage().contains(\"Invalid statement handle\")) { int h = sendPrepare(sql).statementHandle; sendExecuteStatement(h, params); } else throw e;\n}","preventionTips":["Invalidate cached handles on FREE/reconnect.","Execute only handles obtained from prepare on the same connection."],"tags":["firebird","prepared-statement","statement-handle","protocol-ordering"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}