apache/maven · error · MavenException

Unknown lifecycle phase "{}". You must specify a valid lifec

Error message

Unknown lifecycle phase "{}". You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: {}.

What it means

The concurrent BuildPlanExecutor resolves each task's phase (after stripping optional AFTER= and @ prefixes used for ordering/execution-id) against all registered lifecycles; when no lifecycle contains the phase name, it throws MavenException wrapping LifecyclePhaseNotFoundException, including the full list of valid phase names.

Source

Thrown at impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java:984

                Map<MavenProject, List<MavenProject>> projects, String lifecyclePhase) {

            String resolvedPhase = getResolvedPhase(lifecyclePhase);
            String mainPhase = resolvedPhase.startsWith(BEFORE)
                    ? resolvedPhase.substring(BEFORE.length())
                    : resolvedPhase.startsWith(AFTER)
                            ? resolvedPhase.substring(AFTER.length())
                            : resolvedPhase.startsWith(AT) ? resolvedPhase.substring(AT.length()) : resolvedPhase;

            /*
             * Determine the lifecycle that corresponds to the given phase.
             */
            Lifecycle lifecycle = lifecycles.stream()
                    .filter(l -> l.allPhases().anyMatch(p -> mainPhase.equals(p.name())))
                    .findFirst()
                    .orElse(null);

            if (lifecycle == null) {
                throw new MavenException(new LifecyclePhaseNotFoundException(
                        "Unknown lifecycle phase \"" + lifecyclePhase
                                + "\". You must specify a valid lifecycle phase"
                                + " or a goal in the format <plugin-prefix>:<goal> or"
                                + " <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: "
                                + lifecycles.stream()
                                        .flatMap(l -> l.allPhases().map(Lifecycle.Phase::name))
                                        .collect(Collectors.joining(", "))
                                + ".",
                        lifecyclePhase));
            }

            return calculateLifecycleMappings(projects, lifecycle, resolvedPhase);
        }

        public BuildPlan calculateLifecycleMappings(
                Map<MavenProject, List<MavenProject>> projects, Lifecycle lifecycle, String lifecyclePhase) {
            BuildPlan plan = new BuildPlan(projects);

View on GitHub (pinned to e4093d4e12)

Solutions

  1. Match your phase against the 'Available lifecycle phases are:' list in the message and fix the typo
  2. For plugin goals use <plugin-prefix>:<goal> or <groupId>:<artifactId>[:<version>]:<goal> syntax
  3. Ensure the extension that contributes your custom lifecycle is loaded before the build plan is computed
  4. Validate generated phase strings in scripts before passing them to Maven

Example fix

# before
mvn pakage@fast   # 'pakage' is not a phase

# after
mvn package@fast
Defensive patterns

Strategy: validation

Validate before calling

// validate task strings against registered lifecycles before planning
Set<String> phases = lifecycles.stream().flatMap(l -> l.allPhases().map(Lifecycle.Phase::name)).collect(Collectors.toSet());
String main = resolvedPhase.startsWith("+/") ? resolvedPhase.substring(2) : resolvedPhase;
if (!phases.contains(main)) throw new IllegalArgumentException("Unknown phase: " + lifecyclePhase);

Type guard

boolean isKnownPhase(String task, Set<String> phases) {
    String main = task.startsWith("+") ? task.substring(1) : task;
    int at = main.indexOf('@');
    if (at >= 0) main = main.substring(0, at);
    return phases.contains(main) || main.contains(":"); // plugin:goal form
}

Try / catch

catch (MavenException e) {
    if (e.getCause() instanceof LifecyclePhaseNotFoundException nfe) {
        // nfe.getLifecyclePhase() names the bad phase; fix typo or load the custom lifecycle extension
    }
}

Prevention

When it happens

Trigger: Using the concurrent execution path with an invalid phase string — a typo like 'pakage', a phase only defined by an unloaded extension's custom lifecycle, or a malformed 'phase@execution-id' where mainPhase does not exist in any lifecycle.

Common situations: Typos in CLI goals or in <default-goal>; referencing custom lifecycle phases (e.g. from Tycho or document lifecycles) without the defining extension; scripts building 'phase@id' strings dynamically and emitting an empty/garbage phase.

Related errors


AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21). Data as JSON: /api/errors/7b811eafb092f34c. Report an issue: GitHub.