apache/seatunnel · warning

Tunnel deletion failed due to not found:

Error message

Tunnel deletion failed due to not found: 

What it means

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.

Solutions

  1. No action required if the tunnel is intentionally gone — the warning is expected on idempotent cleanup.
  2. Check the OTS console to confirm the tunnel for the table no longer exists and no consumer groups still need it.
  3. 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.

Example fix

// before: exception details are swallowed
} catch (Exception be) {
    log.warn("Tunnel deletion failed due to not found: " + tunnelName);
}
// after: log the cause for diagnosability
} catch (Exception be) {
    log.warn("Tunnel deletion failed for tunnel {}: {}", tunnelName, be.getMessage(), be);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before deleting, check tunnel exists
ListTunnelResponse lresp = tunnelClient.listTunnel(new ListTunnelRequest(tableName));
boolean exists = lresp.getTunnels().stream().anyMatch(t -> t.getTunnelName().equals(tunnelName));

Try / catch

try {
    tunnelClient.deleteTunnel(drequest);
} catch (TableStoreException e) {
    if (!"OTSObjectNotExist".equals(e.getErrorCode())) {
        throw e; // only swallow genuine not-found
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/ae8e4dfd737ec845. Report an issue: GitHub.

Appendix: source

Thrown at seatunnel-connectors-v2/connector-tablestore/src/main/java/org/apache/seatunnel/connectors/seatunnel/tablestore/source/TableStoreSourceReader.java:154

            CreateTunnelRequest crequest =
                    new CreateTunnelRequest(
                            split.getTableName(), tunnelName, TunnelType.valueOf("BaseAndStream"));
            CreateTunnelResponse cresp = tunnelClient.createTunnel(crequest);
            tunnelId = cresp.getTunnelId();
        }
        log.info("Tunnel found, Id: " + tunnelId);
        return tunnelId;
    }

    public void deleteTunel(TableStoreSourceSplit split) {
        String tunnelName = split.getTableName() + "_migration2aws_tunnel4" + split.getSplitId();
        try {
            DeleteTunnelRequest drequest =
                    new DeleteTunnelRequest(split.getTableName(), tunnelName);
            DeleteTunnelResponse dresp = tunnelClient.deleteTunnel(drequest);
            log.info("Tunnel has been deleted: " + dresp.toString());
        } catch (Exception be) {
            log.warn("Tunnel deletion failed due to not found: " + tunnelName);
        }
    }

    @Override
    public List<TableStoreSourceSplit> snapshotState(long checkpointId) throws Exception {
        return new ArrayList<>(pendingSplits);
    }

    @Override
    public void addSplits(List<TableStoreSourceSplit> splits) {
        this.pendingSplits.addAll(splits);
    }

    @Override
    public void handleNoMoreSplits() {
        log.info("Reader [{}] received noMoreSplit event.", context.getIndexOfSubtask());
        noMoreSplit = true;
    }

View on GitHub (pinned to cf67b549a7)