kestra-io/kestra · error · IllegalArgumentException

Invalid target state: {state}. Valid states are: {VALID_TARG

Error message

Invalid target state: {state}. Valid states are: {VALID_TARGET_STATES}

What it means

The `ConcurrencyLimitService.unqueue()` method only allows transitions to three target states: `RUNNING`, `CANCELLED`, and `FAILED` (defined in `VALID_TARGET_STATES`). If any other `State.Type` is passed (e.g., `SUCCESS`, `PAUSED`, `KILLED`), an `IllegalArgumentException` is thrown. These states represent the valid outcomes of releasing a queued execution.

Source

Thrown at core/src/main/java/io/kestra/core/services/ConcurrencyLimitService.java:35

    @Inject
    private ExecutionQueuedStateStore executionQueuedStateStore;

    /**
     * Unqueue a queued execution.
     *
     * @throws IllegalArgumentException in case the execution is not queued or is transitioned to an unsupported state.
     */
    public Execution unqueue(Execution execution, State.Type state) {
        if (execution.getState().getCurrent() != State.Type.QUEUED) {
            throw new IllegalArgumentException("Only QUEUED execution can be unqueued");
        }

        state = (state == null) ? State.Type.RUNNING : state;

        // Validate the target state, throwing an exception if the state is invalid
        if (!VALID_TARGET_STATES.contains(state)) {
            throw new IllegalArgumentException("Invalid target state: " + state + ". Valid states are: " + VALID_TARGET_STATES);
        }

        executionQueuedStateStore.remove(execution);

        return execution.withState(state);
    }
}

View on GitHub (pinned to 823fada927)

Solutions

  1. Use one of the valid target states: RUNNING (start it), CANCELLED (cancel it), or FAILED (fail it).
  2. For SUCCESS, let the execution run and complete normally rather than forcing the state at unqueue time.
  3. If you need PAUSED, the execution must run first and then be paused, not transitioned directly from QUEUED.

Example fix

// before
executionService.unqueue(execution, State.Type.SUCCESS);
// after
executionService.unqueue(execution, State.Type.RUNNING);
Defensive patterns

Strategy: validation

Validate before calling

// Validate target state before calling unqueue
import io.kestra.core.models.flows.State;
import java.util.EnumSet;

private static final Set<State.Type> VALID = EnumSet.of(State.Type.RUNNING, State.Type.CANCELLED, State.Type.FAILED);

public static State.Type validateUnqueueTargetState(State.Type state) {
    if (state == null) return State.Type.RUNNING;
    if (!VALID.contains(state)) {
        throw new IllegalArgumentException("Invalid target state: " + state + ". Valid: " + VALID);
    }
    return state;
}

Type guard

const VALID_UNQUEUE_STATES = new Set(['RUNNING', 'CANCELLED', 'FAILED']);

function isValidUnqueueState(state: string): boolean {
    return VALID_UNQUEUE_STATES.has(state);
}

Prevention

When it happens

Trigger: Calling `unqueue(execution, State.Type.SUCCESS)` or `unqueue(execution, State.Type.PAUSED)`. Passing a state that is semantically inappropriate for an unqueue operation (SUCCESS must come from task completion, not from unqueuing).

Common situations: A developer assumes any terminal state is valid. A caller tries to mark a queued execution as SUCCESS to skip it, but SUCCESS is not a valid unqueue target.

Related errors


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