hashicorp/nomad · error

scheduler resulted in an unexpected number of plans: %v

Error message

scheduler resulted in an unexpected number of plans: %v

What it means

Job.Plan ran the scheduler worker for the evaluation, expecting exactly one scheduling plan back, but got a different count. A count of 0 usually means the scheduler produced no plan for the proposed job; >1 indicates an internal scheduler invariant violation. The endpoint aborts annotation and returns the count.

Source

Thrown at nomad/job_endpoint.go:1908

	// Create an in-memory Planner that returns no errors and stores the
	// submitted plan and created evals.
	planner := &sstructs.PlanBuilder{
		State: &snap.StateStore,
	}

	// Create the scheduler and run it
	sched, err := scheduler.NewScheduler(eval.Type, j.logger, j.srv.workersEventCh, snap, planner)
	if err != nil {
		return err
	}

	if err := sched.Process(eval); err != nil {
		return err
	}

	// Annotate and store the diff
	if plans := len(planner.Plans); plans != 1 {
		return fmt.Errorf("scheduler resulted in an unexpected number of plans: %v", plans)
	}
	annotations := planner.Plans[0].Annotations
	if args.Diff {
		jobDiff, err := existingJob.Diff(args.Job, true)
		if err != nil {
			return fmt.Errorf("failed to create job diff: %v", err)
		}

		if err := scheduler.Annotate(jobDiff, annotations); err != nil {
			return fmt.Errorf("failed to annotate job diff: %v", err)
		}
		reply.Diff = jobDiff
	}

	// Grab the failures
	if len(planner.Evals) != 1 {
		return fmt.Errorf("scheduler resulted in an unexpected number of eval updates: %v", planner.Evals)
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Inspect server logs around the plan request for scheduler errors explaining why no plan was produced.
  2. Retry the plan request; transient worker issues can yield zero plans.
  3. Validate the job type and placement constraints ('nomad job validate') to ensure a scheduler can process it.
  4. If reproducible (especially plans > 1), capture a nomad operator debug bundle and file a bug — this path should be invariant.
Defensive patterns

Strategy: retry

Validate before calling

// Ensure the job type is schedulable before planning
if *job.Type == "system" || *job.Type == "batch" {
    // verify constraints/placeability with validate first
    if _, _, err := client.Jobs().Validate(job, nil); err != nil { return err }
}

Try / catch

plan, _, err := client.Jobs().Plan(job, true, nil)
if err != nil && strings.Contains(err.Error(), "unexpected number of plans") {
    // one retry after brief backoff; persistent counts (>1) indicate a Nomad bug — capture a debug bundle
}

Prevention

When it happens

Trigger: Job.Plan where after sched.Process(eval), len(planner.Plans) != 1 at nomad/job_endpoint.go:1908 — commonly 0 plans when the planner's SubmitPlan never fired for the fake eval created from args.Job.

Common situations: Planning a job whose constraints/placeability produce no eval work in that scheduler (e.g. system-job edge cases); scheduler worker errors swallowed upstream; Nomad bugs after version upgrades changing plan submission behavior; job type mapping to an unexpected scheduler.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/67761403254fa0c2. Report an issue: GitHub.