apache/seatunnel · error · CheckpointStorageException

No checkpoint found for job ${jobId}

Error message

No checkpoint found for job ${jobId}

What it means

LocalFileStorage.deleteCheckpoint(jobId, pipelineId, checkpointId) throws 'No checkpoint found for job <jobId>' when the job's checkpoint directory lists successfully but contains no checkpoint files at all. The delete API requires existing checkpoints to operate on; an empty job directory is treated as an error rather than a no-op, so callers cannot blindly call delete on already-cleaned jobs.

Source

Thrown at seatunnel-engine/seatunnel-engine-storage/checkpoint-storage-plugins/checkpoint-storage-local-file/src/main/java/org/apache/seatunnel/engine/checkpoint/storage/localfile/LocalFileStorage.java:337

                String.format(
                        "No checkpoint found, job(%s), pipeline(%s), checkpoint(%s)",
                        jobId, pipelineId, checkpointId));
    }

    @Override
    public synchronized void deleteCheckpoint(String jobId, String pipelineId, String checkpointId)
            throws CheckpointStorageException {
        String parentPath = getStorageParentDirectory() + jobId;
        Collection<File> fileList = new ArrayList<>();
        try {
            fileList = FileUtils.listFiles(new File(parentPath), FILE_EXTENSIONS, false);
        } catch (Exception e) {
            if (!(e.getCause() instanceof NoSuchFileException)) {
                throw new CheckpointStorageException(ExceptionUtils.getMessage(e));
            }
        }
        if (fileList.isEmpty()) {
            throw new CheckpointStorageException("No checkpoint found for job " + jobId);
        }
        fileList.forEach(
                file -> {
                    String fileName = file.getName();
                    if (pipelineId.equals(getPipelineIdByFileName(fileName))
                            && checkpointId.equals(getCheckpointIdByFileName(fileName))) {
                        try {
                            FileUtils.delete(file);
                        } catch (Exception e) {
                            log.error(
                                    "Failed to delete checkpoint {} for job {}, pipeline {}",
                                    checkpointId,
                                    jobId,
                                    pipelineId,
                                    e);
                        }
                    }
                });

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Make delete idempotent on your side: check for existing checkpoints (getCheckpointsByJobIdAndPipelineId) before calling deleteCheckpoint and skip when empty.
  2. Catch CheckpointStorageException and treat the 'No checkpoint found for job' message as success in cleanup paths.
  3. Investigate why checkpoints are missing — check earlier logs for failed checkpoint writes.
  4. If deleting a specific pipeline/checkpoint, verify the id strings match exactly what was written (pipeline id and checkpoint id formatting must match).

Example fix

// before
storage.deleteCheckpoint(jobId, pipelineId, checkpointId); // throws if nothing stored
// after
try {
    storage.deleteCheckpoint(jobId, pipelineId, checkpointId);
} catch (CheckpointStorageException e) {
    if (!e.getMessage().contains("No checkpoint found")) {
        throw e;
    }
    log.info("Checkpoints already removed for job {}", jobId);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Only call delete when checkpoints actually exist
if (storage.getCheckpointsByJobIdAndPipelineId(jobId, pipelineId).isEmpty()) {
    return; // nothing to delete
}

Try / catch

try {
    storage.deleteCheckpoint(jobId, pipelineId, checkpointId);
} catch (CheckpointStorageException e) {
    if (e.getMessage().startsWith("No checkpoint found")) {
        log.info("Nothing to delete for job {} — already clean", jobId);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling deleteCheckpoint(jobId, pipelineId, checkpointId) after all checkpoint files were already deleted (e.g. by a prior delete call or external cleanup), or when the job directory exists but is empty because checkpoints were never successfully written.

Common situations: Double-invocation of cleanup logic (job finished listener firing twice); checkpoint writes never happened because the job failed before the first completed checkpoint; an external retention job emptied the directory between listing and delete; id mismatch — files exist for other pipelines but the directory filter yields nothing (note this specific message fires only when the whole job file list is empty).

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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