apache/seatunnel · error · UnknownPhysicalPlanException

The physical plan didn't have any can execute pipeline

Error message

The physical plan didn't have any can execute pipeline

What it means

PhysicalPlan's constructor validates that the submitted physical plan contains at least one executable pipeline; an empty pipelineList throws UnknownPhysicalPlanException with the message that the plan has no executable pipeline. A plan with zero pipelines cannot be scheduled, so the engine rejects it at construction time.

Source

Thrown at seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/dag/physical/PhysicalPlan.java:123

            stateTimestamps[JobStatus.INITIALIZING.ordinal()] = initializationTimestamp;
            runningJobStateTimestampsIMap.put(jobId, stateTimestamps);
        }

        if (runningJobStateIMap.get(jobId) == null) {
            // We must update runningJobStateTimestampsIMap first and then can update
            // runningJobStateIMap.
            // Because if a new Master Node become active, we can recover ExecutionState and
            // PipelineState and JobStatus
            // from TaskExecutionService. But we can not recover stateTimestamps.
            stateTimestamps[JobStatus.CREATED.ordinal()] = System.currentTimeMillis();
            runningJobStateTimestampsIMap.put(jobId, stateTimestamps);

            runningJobStateIMap.put(jobId, JobStatus.CREATED);
        }

        this.pipelineList = pipelineList;
        if (pipelineList.isEmpty()) {
            throw new UnknownPhysicalPlanException(
                    "The physical plan didn't have any can execute pipeline");
        }
        this.jobFullName =
                String.format(
                        "Job %s (%s)",
                        jobImmutableInformation.getJobConfig().getName(),
                        jobImmutableInformation.getJobId());

        this.runningJobStateIMap = runningJobStateIMap;
        this.runningJobStateTimestampsIMap = runningJobStateTimestampsIMap;
    }

    public void setJobMaster(JobMaster jobMaster) {
        this.jobMaster = jobMaster;
        pipelineList.forEach(pipeline -> pipeline.setJobMaster(jobMaster));
        this.engineConfig = jobMaster.getEngineConfig();
    }

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Review the job config: ensure it contains at least a source and a sink so the DAG yields a pipeline
  2. Run the config through the config validator / dry-run (e.g., seatunnel.sh --check) before submission
  3. Check whether plugin discovery failed so source/sink factories were missing and the planner pruned the DAG — look for earlier warnings in the logs
  4. If building plans programmatically, assert the logical plan's pipeline list is non-empty before constructing PhysicalPlan
  5. Verify the connector plugins are installed in the correct connectors directory for your version

Example fix

// before
// config.hocon with only a transform, no source/sink
env { parallelism = 1 }
transform { Sql { source_table_name = "x" } }

// after
env { parallelism = 1 }
source { FakeSource { result_table_name = "x" } }
transform { Sql { source_table_name = "x" } }
sink { Console { source_table_name = "x" } }
Defensive patterns

Strategy: validation

Validate before calling

// before submission
if (logicalPlan == null || logicalPlan.getPipelines().isEmpty()) {
    throw new IllegalArgumentException("Job config produced no pipelines; check source/sink config");
}

Type guard

boolean hasPipelines(LogicalPlan p) { return p != null && !p.getPipelines().isEmpty(); }

Try / catch

try {
    submit(jobConfig);
} catch (UnknownPhysicalPlanException e) {
    LOG.error("Job produced no pipelines — verify source and sink are configured and plugins installed", e);
}

Prevention

When it happens

Trigger: Creating a PhysicalPlan from a logical plan that produced no pipelines — e.g., a job config whose DAG has no source/sink after optimization, all pipelines excluded by filters, or a malformed/empty job configuration.

Common situations: Job config with only a transform and no source/sink; a config error causing the DAG builder to drop all edges/nodes; programmatically built logical plans with empty pipeline lists; version-dependent planner changes that eliminate pipelines.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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