{"record":{"id":"9b00301648cae075","repo":"apache/seatunnel","slug":"should-never-happen-9b0030","errorCode":"SHOULD_NEVER_HAPPEN","errorMessage":"never happen error.","messagePattern":"never happen error\\.","errorType":"error_code","errorClass":"DorisConnectorException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-doris/src/main/java/org/apache/seatunnel/connectors/doris/source/reader/DorisValueReader.java","lineNumber":260,"sourceCode":"                    }\n                }\n                hasNext = !eos.get();\n            } finally {\n                clientLock.unlock();\n            }\n        }\n        return hasNext;\n    }\n\n    /**\n     * get next value.\n     *\n     * @return next value\n     */\n    public SeaTunnelRow next() {\n        if (!hasNext()) {\n            log.error(SHOULD_NOT_HAPPEN_MESSAGE);\n            throw new DorisConnectorException(\n                    DorisConnectorErrorCode.SHOULD_NEVER_HAPPEN, \"never happen error.\");\n        }\n        SeaTunnelRow next = rowBatch.next();\n        next.setTableId(dorisSourceTable.getTablePath().toString());\n        return next;\n    }\n\n    public void close() {\n        clientLock.lock();\n        try {\n            TScanCloseParams closeParams = new TScanCloseParams();\n            closeParams.setContextId(contextId);\n            client.closeScanner(closeParams);\n        } catch (Exception e) {\n            log.error(\"Failed to close reader with context id {}\", contextId, e);\n            throw new DorisConnectorException(DorisConnectorErrorCode.RESOURCE_CLOSE_FAILED, e);\n        } finally {\n            clientLock.unlock();","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-doris/src/main/java/org/apache/seatunnel/connectors/doris/source/reader/DorisValueReader.java#L242-L278","documentation":"DorisValueReader.next() is only valid when rows remain; calling it after the internal row batch is exhausted violates the reader contract, so it throws SHOULD_NEVER_HAPPEN. hasNext() returned false right before the call.","triggerScenarios":"next() invoked when hasNext() is false — e.g. caller keeps calling next() past the end of a partition's rows or after a exhausted rowBatch refill failure.","commonSituations":"Custom/patched reader loop ignoring hasNext(); race where the underlying Doris reader exhausted early due to empty partitions; connector bug in batch boundary handling.","solutions":["Guard every next() call with hasNext()","If it occurs inside stock code, file a bug with the split/partition info and full stacktrace","Check whether the partition produced an empty/failed read that skipped refill logic","Pin to a fixed connector version if this is a known regression"],"exampleFix":"// before\nwhile (true) { row = valueReader.next(); ... }\n// after\nwhile (valueReader.hasNext()) { row = valueReader.next(); ... }","handlingStrategy":"type-guard","validationCode":"if (valueReader.hasNext()) { row = valueReader.next(); }","typeGuard":"boolean safe = valueReader != null && valueReader.hasNext();","tryCatchPattern":"try { row = valueReader.next(); } catch (DorisConnectorException e) { if (e.getMessage().contains(\"never happen\")) { LOG.error(\"exhausted reader; report bug with partition info\"); } throw e; }","preventionTips":["Always gate next() behind hasNext()","Don't modify reader iteration logic in custom patches","Report reproducible cases to the connector maintainers"],"tags":["doris","source","iterator","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}