{"record":{"id":"ae8e4dfd737ec845","repo":"apache/seatunnel","slug":"tunnel-deletion-failed-due-to-not-found","errorCode":null,"errorMessage":"Tunnel deletion failed due to not found: ","messagePattern":"Tunnel deletion failed due to not found: ","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-tablestore/src/main/java/org/apache/seatunnel/connectors/seatunnel/tablestore/source/TableStoreSourceReader.java","lineNumber":154,"sourceCode":"            CreateTunnelRequest crequest =\n                    new CreateTunnelRequest(\n                            split.getTableName(), tunnelName, TunnelType.valueOf(\"BaseAndStream\"));\n            CreateTunnelResponse cresp = tunnelClient.createTunnel(crequest);\n            tunnelId = cresp.getTunnelId();\n        }\n        log.info(\"Tunnel found, Id: \" + tunnelId);\n        return tunnelId;\n    }\n\n    public void deleteTunel(TableStoreSourceSplit split) {\n        String tunnelName = split.getTableName() + \"_migration2aws_tunnel4\" + split.getSplitId();\n        try {\n            DeleteTunnelRequest drequest =\n                    new DeleteTunnelRequest(split.getTableName(), tunnelName);\n            DeleteTunnelResponse dresp = tunnelClient.deleteTunnel(drequest);\n            log.info(\"Tunnel has been deleted: \" + dresp.toString());\n        } catch (Exception be) {\n            log.warn(\"Tunnel deletion failed due to not found: \" + tunnelName);\n        }\n    }\n\n    @Override\n    public List<TableStoreSourceSplit> snapshotState(long checkpointId) throws Exception {\n        return new ArrayList<>(pendingSplits);\n    }\n\n    @Override\n    public void addSplits(List<TableStoreSourceSplit> splits) {\n        this.pendingSplits.addAll(splits);\n    }\n\n    @Override\n    public void handleNoMoreSplits() {\n        log.info(\"Reader [{}] received noMoreSplit event.\", context.getIndexOfSubtask());\n        noMoreSplit = true;\n    }","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-tablestore/src/main/java/org/apache/seatunnel/connectors/seatunnel/tablestore/source/TableStoreSourceReader.java#L136-L172","documentation":"TableStoreSourceReader.deleteTunel deletes the OTS tunnel associated with a finished split. If tunnelClient.deleteTunnel throws (typically because the tunnel no longer exists, TableStore error code OTSObjectNotExist), the reader only logs this warning and swallows the exception. The connector treats 'already gone' as success so snapshot cleanup is idempotent.","triggerScenarios":"deleteTunel(split, tunnelName) is called (from getTunel cleanup after a split is fully consumed) and the tunnel was already deleted — e.g. by a previous checkpoint restart, a parallel reader instance, or manual cleanup — so TableStore returns a not-found error.","commonSituations":"Job restarted after tunnel deletion succeeded but before state was committed; two readers racing to clean up the same tunnel; operator deleted tunnels manually via the OTS console while the job was running.","solutions":["No action required if the tunnel is intentionally gone — the warning is expected on idempotent cleanup.","Check the OTS console to confirm the tunnel for the table no longer exists and no consumer groups still need it.","If deletions fail persistently with other errors, inspect the swallowed exception `be` (add logging of be.getMessage()) to distinguish not-found from permission/network failures."],"exampleFix":"// before: exception details are swallowed\n} catch (Exception be) {\n    log.warn(\"Tunnel deletion failed due to not found: \" + tunnelName);\n}\n// after: log the cause for diagnosability\n} catch (Exception be) {\n    log.warn(\"Tunnel deletion failed for tunnel {}: {}\", tunnelName, be.getMessage(), be);\n}","handlingStrategy":"try-catch","validationCode":"// before deleting, check tunnel exists\nListTunnelResponse lresp = tunnelClient.listTunnel(new ListTunnelRequest(tableName));\nboolean exists = lresp.getTunnels().stream().anyMatch(t -> t.getTunnelName().equals(tunnelName));","typeGuard":null,"tryCatchPattern":"try {\n    tunnelClient.deleteTunnel(drequest);\n} catch (TableStoreException e) {\n    if (!\"OTSObjectNotExist\".equals(e.getErrorCode())) {\n        throw e; // only swallow genuine not-found\n    }\n}","preventionTips":["Only treat OTSObjectNotExist as an expected skip; rethrow other errors","Log the swallowed exception's message/cause for diagnosability","Avoid manual tunnel deletion while a reader job is active"],"tags":["tablestore","aliyun-ots","tunnel","cleanup"],"backgroundTag":"resource-not-found","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"}