{"record":{"id":"36c9b65cd5ba0a94","repo":"apache/seatunnel","slug":"never-happen-error","errorCode":null,"errorMessage":"never happen error !","messagePattern":"never happen error !","errorType":"exception","errorClass":"ClickhouseConnectorException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/source/ClickhouseValueReader.java","lineNumber":109,"sourceCode":"        this.shouldUseStreamReader = shouldUseStreamReader();\n    }\n\n    public boolean hasNext() {\n        if (shouldUseStreamReader) {\n            if (streamValueReader == null) {\n                streamValueReader = new StreamValueReader();\n            }\n            return streamValueReader.hasNext();\n        } else if (clickhouseSourceTable.isSqlStrategyRead()) {\n            return sqlBatchStrategyRead();\n        } else {\n            return partBatchStrategyRead();\n        }\n    }\n\n    public List<SeaTunnelRow> next() {\n        if (rowBatch == null) {\n            throw new ClickhouseConnectorException(\n                    ClickhouseConnectorErrorCode.SHOULD_NEVER_HAPPEN, \"never happen error !\");\n        }\n\n        return rowBatch;\n    }\n\n    private boolean partBatchStrategyRead() {\n        List<ClickhousePart> parts = clickhouseSourceSplit.getParts();\n        int partSize = parts.size();\n\n        if (currentPartIndex >= partSize) {\n            return false;\n        }\n\n        ClickhousePart currentPart = parts.get(currentPartIndex);\n\n        // If current part has been processed, move to the next part\n        if (currentPart.isEndOfPart()) {","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/source/ClickhouseValueReader.java#L91-L127","documentation":"This ClickhouseConnectorException with SHOULD_NEVER_HAPPEN is thrown by ClickhouseValueReader.next() when the internal rowBatch field is null. It signals an internal invariant violation: the reader's batching strategy was never initialized (no prior hasNext()/read produced a batch), so there is no row batch to return. Callers must always drive the reader through hasNext() before calling next().","triggerScenarios":"Calling next() on a ClickhouseValueReader whose rowBatch is null — i.e., next() is invoked before any successful hasNext()/batch-read call, or after the reader was constructed but never advanced, or when no batching strategy was configured.","commonSituations":"Custom or patched source reader code that calls next() without first calling hasNext(); a reader deserialized/reinitialized after failure where rowBatch was never populated; misuse of the reader API outside the normal SourceReader poll loop.","solutions":["Always call hasNext() and only call next() when it returns true — this initializes rowBatch via partBatchStrategyRead()/sqlBatchStrategyRead()","Check that the split was properly opened/initialized before reading (reader state set up in the split enumerator/reader lifecycle)","If this occurs in normal SeaTunnel flow, enable debug logging on the reader and file a bug with the split/shard info since it indicates an internal state bug","Ensure the split being read actually matched a ClickHouse part/shard so a batching strategy was selected"],"exampleFix":"// before\nList<SeaTunnelRow> rows = reader.next();\n// after\nif (reader.hasNext()) {\n    List<SeaTunnelRow> rows = reader.next();\n}","handlingStrategy":"type-guard","validationCode":"// Java: guard before consuming\nif (!reader.hasNext()) {\n    throw new IllegalStateException(\"Reader has no batch; hasNext() must be called before next()\");\n}","typeGuard":"boolean canRead(ClickhouseValueReader reader) {\n    try {\n        return reader.hasNext();\n    } catch (Exception e) {\n        return false;\n    }\n}","tryCatchPattern":"try {\n    rows = reader.next();\n} catch (ClickhouseConnectorException e) {\n    if (e.getErrorCode() == ClickhouseConnectorErrorCode.SHOULD_NEVER_HAPPEN) {\n        // reinitialize the reader/split and retry from checkpoint\n    }\n    throw e;\n}","preventionTips":["Only call next() after hasNext() returns true, mirroring the SeaTunnel SourceReader poll loop","Never cache a reader across failures without re-opening/re-initializing the split","Treat SHOULD_NEVER_HAPPEN as a bug report: capture split id and shard and report it"],"tags":["clickhouse","internal-state","source-reader"],"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-14T05:17:10.506Z"}