{"record":{"id":"e7e874b4e749dc0e","repo":"apache/seatunnel","slug":"failed-to-advance-next-batch-id","errorCode":null,"errorMessage":"Failed to advance next_batch_id","messagePattern":"Failed to advance next_batch_id","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"critical","filePath":"seatunnel-edge-agent/seatunnel-edge-agent-starter/src/main/java/org/apache/seatunnel/edge/agent/starter/wal/sqlite/SqliteBatchIdAllocator.java","lineNumber":45,"sourceCode":"    /**\n     * Returns the next batch id and advances the counter. Must run inside an open transaction on\n     * {@code connection}.\n     */\n    public static long allocateNext(Connection connection) throws SQLException {\n        Long current = readNextBatchId(connection);\n        if (current == null) {\n            seedMetaFromWal(connection);\n            current = readNextBatchId(connection);\n        }\n        if (current == null || current <= 0) {\n            throw new SQLException(\"Failed to initialize next_batch_id in edge_agent_meta\");\n        }\n        try (PreparedStatement statement =\n                connection.prepareStatement(MetaSqlStatements.UPDATE_VALUE)) {\n            statement.setLong(1, current + 1);\n            statement.setString(2, MetaSqlStatements.KEY_NEXT_BATCH_ID);\n            if (statement.executeUpdate() != 1) {\n                throw new SQLException(\"Failed to advance next_batch_id\");\n            }\n        }\n        return current;\n    }\n\n    public static Long peekNextBatchId(Connection connection) throws SQLException {\n        return readNextBatchId(connection);\n    }\n\n    public static void seedMetaFromWal(Connection connection) throws SQLException {\n        try (PreparedStatement statement =\n                connection.prepareStatement(MetaSqlStatements.SEED_NEXT_BATCH_ID_FROM_WAL)) {\n            statement.executeUpdate();\n        }\n    }\n\n    private static Long readNextBatchId(Connection connection) throws SQLException {\n        try (PreparedStatement statement =","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-edge-agent/seatunnel-edge-agent-starter/src/main/java/org/apache/seatunnel/edge/agent/starter/wal/sqlite/SqliteBatchIdAllocator.java#L27-L63","documentation":"allocateNext() advances the next_batch_id row by writing current+1 and requires exactly one affected row. If the UPDATE affects 0 rows, the meta key was deleted (or the row vanished) between the read and the write, so the allocator cannot persist the id advance and throws this SQLException.","triggerScenarios":"Calling allocateNext(connection) where UPDATE_VALUE on key 'next_batch_id' matches no rows — typically because the edge_agent_meta row was deleted concurrently or the table was recreated mid-call.","commonSituations":"Concurrent access to the same sqlite database from two agent processes; manual DELETE/maintenance scripts touching edge_agent_meta while the agent runs; a transaction/rollback race wiping the key.","solutions":["Ensure only one agent process accesses the sqlite file at a time (sqlite allows only a single writer).","Restore the next_batch_id row in edge_agent_meta and restart the agent.","Avoid external maintenance scripts that delete rows from edge_agent_meta while the agent is running.","Enable sqlite WAL journal mode and retry the allocation if transient locking is suspected."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"try (PreparedStatement ps = connection.prepareStatement(\"SELECT COUNT(*) FROM edge_agent_meta WHERE key='next_batch_id'\")) { try (ResultSet rs = ps.executeQuery()) { rs.next(); if (rs.getInt(1) != 1) { /* restore row before allocating */ } } }","typeGuard":null,"tryCatchPattern":"catch (SQLException e) { if (e.getMessage().contains(\"Failed to advance next_batch_id\")) { recreateMetaRow(); retryAllocate(); } else { throw e; } }","preventionTips":["Run only one agent process against the sqlite file.","Avoid concurrent maintenance scripts on edge_agent_meta.","Use sqlite WAL journal mode for safer concurrent reads.","Wrap meta updates in short transactions to reduce race windows."],"tags":["sqlite","wal","batch-id","race-condition"],"backgroundTag":"database-write-failed","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}