kestra-io/kestra · error · IllegalStateException

Cannot repair migration script [<scriptId>] because it has n

Error message

Cannot repair migration script [<scriptId>] because it has not been applied.

What it means

Thrown by repairChecksum() when historyStore.isApplied(scriptId) returns false — the script was never executed against the backend, so there is no stored checksum row to update. Repair is only meaningful for scripts already recorded in migration history. This is an IllegalStateException (not argument) signalling the requested operation is invalid for the current backend state.

Source

Thrown at core/src/main/java/io/kestra/core/migration/MigrationRunner.java:151

    public void repairChecksum(final String scriptId) throws MigrationLockedException, Exception {
        if (!lock.tryAcquire()) {
            throw new MigrationLockedException();
        }

        try {
            historyStore.bootstrapIfNeeded();

            MigrationScript script = scripts.stream()
                .filter(candidate -> candidate.scriptId().equals(scriptId))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("Unknown migration script [" + scriptId + "]."));

            if (script.checksum() == null) {
                throw new IllegalArgumentException("Migration script [" + scriptId + "] has no checksum to repair.");
            }

            if (!historyStore.isApplied(scriptId)) {
                throw new IllegalStateException("Cannot repair migration script [" + scriptId + "] because it has not been applied.");
            }

            historyStore.updateChecksum(script);
            log.info("Migration checksum repaired for script [{}].", scriptId);
        } finally {
            lock.release();
        }
    }

    /**
     * Returns all scripts that have not yet been applied, sorted by {@code scriptId}.
     * Used by EE to detect pending scripts before deciding whether to run or fail.
     *
     * <p>
     * This method does <strong>not</strong> acquire the migration lock. It is intended as a
     * read-only startup check on a single node (EE {@code auto=false} path) to decide whether to
     * throw {@link MigrationPendingException}. In multi-node deployments, callers should be aware
     * that another node may concurrently apply migrations between this call and any subsequent action.

View on GitHub (pinned to 823fada927)

Solutions

  1. Run 'kestra migrate' to apply pending scripts first.
  2. After migration completes, re-run 'kestra migrate repair <scriptId>' if a checksum drift still exists.
  3. If the script should already be applied, verify the history table is not corrupt or truncated.

Example fix

// before
$ kestra migrate repair 0_009_xyz
// IllegalStateException: not applied

// after
$ kestra migrate            // apply first
$ kestra migrate repair 0_009_xyz
Defensive patterns

Strategy: validation

Validate before calling

if (!historyStore.isApplied(scriptId)) {
    log.warn("Script {} not applied yet; run migrations before repair.", scriptId);
    return;
}

Try / catch

try {
    migrationRunner.repairChecksum(scriptId);
} catch (IllegalStateException e) {
    log.warn("Cannot repair {}: {}", scriptId, e.getMessage());
    // run 'kestra migrate' first, then retry
}

Prevention

When it happens

Trigger: Calling repair on a pending (not-yet-applied) migration script; calling repair before any migrations have run on a fresh instance; the history store bootstrap recorded the script as absent.

Common situations: New script added that has not yet been executed; operator assumes a script ran but it was skipped; fresh database where history is empty.

Related errors


AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14). Data as JSON: /api/errors/33f77b507a342dd2. Report an issue: GitHub.