apache/maven · warning
Illegal call to phase '{}'. The main phase '{}' will be used
Error message
Illegal call to phase '{}'. The main phase '{}' will be used instead. What it means
Maven 4 decorates every lifecycle phase with implicit 'before:<phase>' and 'after:<phase>' sub-phases (Lifecycle.BEFORE/Lifecycle.AFTER prefixes). calculateTaskSegments detects a task string starting with those prefixes, strips it down to the main phase via PhaseId.of(task).phase(), warns that the call was illegal, and schedules the main phase - so 'mvn before:compile' builds up to and including compile, not just the pre-step.
Source
Thrown at impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleTaskSegmentCalculator.java:106
}
return calculateTaskSegments(session, tasks);
}
@Override
public List<TaskSegment> calculateTaskSegments(MavenSession session, List<String> tasks)
throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
PluginVersionResolutionException {
List<TaskSegment> taskSegments = new ArrayList<>(tasks.size());
TaskSegment currentSegment = null;
for (String task : tasks) {
if (isBeforeOrAfterPhase(task)) {
String prevTask = task;
task = PhaseId.of(task).phase();
LOGGER.warn("Illegal call to phase '{}'. The main phase '{}' will be used instead.", prevTask, task);
}
if (isGoalSpecification(task)) {
// "pluginPrefix[:version]:goal" or "groupId:artifactId[:version]:goal"
lifecyclePluginResolver.resolveMissingPluginVersions(session.getTopLevelProject(), session);
MojoDescriptor mojoDescriptor =
mojoDescriptorCreator.getMojoDescriptor(task, session, session.getTopLevelProject());
boolean aggregating = mojoDescriptor.isAggregator() || !mojoDescriptor.isProjectRequired();
if (currentSegment == null || currentSegment.isAggregating() != aggregating) {
currentSegment = new TaskSegment(aggregating);
taskSegments.add(currentSegment);
}
currentSegment.getTasks().add(new GoalTask(task));
} else {View on GitHub (pinned to e4093d4e12)
Solutions
- Invoke the plain phase instead: mvn compile rather than mvn before:compile / mvn after:compile
- If you only want pre/post hooks, bind your plugin executions to the standard phases in the POM
- For programmatic invocations, sanitize the task list by stripping before:/after: prefixes before calling Maven
Example fix
# before mvn after:package # warns; runs 'package' itself mvn before:compile # warns; runs 'compile' itself # after mvn package mvn compile
Defensive patterns
Strategy: validation
Validate before calling
// programmatic invocation: strip illegal before:/after: prefixes before calling Maven
List<String> sanitized = tasks.stream()
.map(t -> t.startsWith("before:") || t.startsWith("after:") ? t.substring(t.indexOf(':') + 1) : t)
.distinct()
.collect(Collectors.toList()); Prevention
- Invoke plain phase names (mvn compile, mvn package) - before:/after: sub-phases are internal
- When listing phases for users, filter out the before:/after: variants
- Treat this warning as a sign a script generated the wrong task names
When it happens
Trigger: Passing before:<phase> or after:<phase> as a goal on the command line or via MavenSession goals programmatically; the before/after sub-phases are internal stepping stones, not directly invocable tasks.
Common situations: Users experimenting with Maven 4 phase syntax; scripts generated from phase listings that include the synthetic before:/after: entries; IDE task templates listing all phases.
Related errors
- Illegal call to phase '{}'. The main phase '{}' will be used
- Found duplicated phase '{}' in '{}' lifecycle
- Unable to load plugin lifecycles
- Unknown lifecycle phase "{}". You must specify a valid lifec
- No goals have been specified for this build. You must specif
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/e116343c5cc5cddd.
Report an issue: GitHub.