hashicorp/nomad · error

missing job ID for marking job as stable

Error message

missing job ID for marking job as stable

What it means

The Stable RPC marks a deployment of a specific job version as stable. Its argument validation requires a job ID; when args.JobID is the empty string it returns "missing job ID for marking job as stable" before touching the state store. This is pure input validation of the JobStableRequest.

Source

Thrown at nomad/job_endpoint.go:646

	j.srv.MeasureRPCRate("job", structs.RateMetricWrite, args)
	if authErr != nil {
		return structs.ErrPermissionDenied
	}
	defer metrics.MeasureSince([]string{"nomad", "job", "stable"}, time.Now())

	// Check for read-job permissions
	if aclObj, err := j.srv.ResolveACL(args); err != nil {
		return err
	} else if !aclObj.AllowNsOpAnyOf(args.RequestNamespace(),
		acl.NamespaceCapabilitySubmitJob,
		acl.NamespaceCapabilityStableJob,
	) {
		return structs.ErrPermissionDenied
	}

	// Validate the arguments
	if args.JobID == "" {
		return fmt.Errorf("missing job ID for marking job as stable")
	}

	// Lookup the job by version
	snap, err := j.srv.fsm.State().Snapshot()
	if err != nil {
		return err
	}

	ws := memdb.NewWatchSet()
	jobV, err := snap.JobByIDAndVersion(ws, args.RequestNamespace(), args.JobID, args.JobVersion)
	if err != nil {
		return err
	}
	if jobV == nil {
		return fmt.Errorf("job %q in namespace %q at version %d not found", args.JobID, args.RequestNamespace(), args.JobVersion)
	}

	// Commit this stability request via Raft

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set JobID on the JobStableRequest before calling the RPC
  2. Validate the job ID is non-empty in your tooling before issuing the request
  3. If the ID comes from a variable/config, log it and fix the interpolation or config source
  4. Use the CLI (`nomad job eval`-adjacent workflows or deployment tooling) which fills the ID automatically

Example fix

// before
args := &nomad.JobStableRequest{JobVersion: 5, Stable: true}
// after
args := &nomad.JobStableRequest{JobID: "webapp", JobVersion: 5, Stable: true}
Defensive patterns

Strategy: validation

Validate before calling

if jobID == "" {
    return fmt.Errorf("refusing to call Stable RPC: empty job ID")
}

Type guard

func validJobStableRequest(a *api.JobStableRequest) bool { return a != nil && a.JobID != "" }

Try / catch

_, _, err := client.Jobs().Stable(args, wo)
if err != nil && strings.Contains(err.Error(), "missing job ID") {
    // request was built without JobID: fix request construction
}

Prevention

When it happens

Trigger: Calling the Job.Stable RPC (POST /v1/job/<id>/stable) with a JobStableRequest whose JobID field is unset/empty — typically building the request programmatically and forgetting to set JobID, or deserializing a request where the ID was dropped.

Common situations: Hand-rolled API calls or automation constructing JobStableRequest structs; templates/CI scripts where the job ID variable interpolates to empty; SDK wrappers that fail to propagate the ID parameter.

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/23923b380117ae8a. Report an issue: GitHub.