hashicorp/nomad · error

Job required for plan

Error message

Job required for plan

What it means

Job.Plan was called without a Job payload. The plan endpoint evaluates a proposed job against the cluster without registering it, so a nil args.Job means there is nothing to evaluate; the request is rejected with 'Job required for plan'.

Source

Thrown at nomad/job_endpoint.go:1777

	return nil
}

// Plan is used to cause a dry-run evaluation of the Job and return the results
// with a potential diff containing annotations.
func (j *Job) Plan(args *structs.JobPlanRequest, reply *structs.JobPlanResponse) error {
	authErr := j.srv.Authenticate(j.ctx, args)
	if done, err := j.srv.forward("Job.Plan", args, args, reply); done {
		return err
	}
	j.srv.MeasureRPCRate("job", structs.RateMetricWrite, args)
	if authErr != nil {
		return structs.ErrPermissionDenied
	}
	defer metrics.MeasureSince([]string{"nomad", "job", "plan"}, time.Now())

	// Validate the arguments
	if args.Job == nil {
		return fmt.Errorf("Job required for plan")
	}

	// Run admission controllers
	job, warnings, err := j.admissionControllers(args.Job)
	if err != nil {
		return err
	}
	args.Job = job

	// Set the warning message
	reply.Warnings = helper.MergeMultierrorWarnings(warnings...)

	// Check job submission permissions, which we assume is the same for plan
	if aclObj, err := j.srv.ResolveACL(args); err != nil {
		return err
	} else {
		if !aclObj.AllowNsOpAnyOf(args.RequestNamespace(),
			acl.NamespaceCapabilitySubmitJob,

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Supply a fully parsed structs.Job in the request body before calling Plan.
  2. Run 'nomad job validate' / the parse API on the HCL first and abort on parse failure.
  3. Check that the config file actually loaded (empty file or wrong path yields a nil/empty job).
  4. Construct the job programmatically and assert non-nil before submitting the plan request.

Example fix

// before
job, err := jobspec.Parse(f) // err ignored, job nil
plan, _, err := client.Jobs().Plan(job, true, nil)
// after
job, err := jobspec.Parse(f)
if err != nil { return err }
if job == nil { return errors.New("parsed job is nil") }
plan, _, err := client.Jobs().Plan(job, true, nil)
Defensive patterns

Strategy: validation

Validate before calling

if job == nil {
    return fmt.Errorf("nothing to plan: parsed job is nil")
}
if _, _, err := client.Jobs().Validate(job, nil); err != nil { return err }
plan, _, err := client.Jobs().Plan(job, diff, nil)

Type guard

func jobProvided(j *api.Job) bool { return j != nil && j.ID != nil && *j.ID != "" }

Prevention

When it happens

Trigger: POST /v1/job/plan with an empty or missing Job object in the body (client.Jobs().Plan(nil, true, nil)) after ACL checks, at nomad/job_endpoint.go:1777.

Common situations: Dry-run tooling serializing a nil job; HCL/JSON job spec that failed to parse into a structs.Job yet the code proceeded; calling the raw endpoint with an empty POST body.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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