hashicorp/nomad · error

job does not have allocation

Error message

job %s does not have allocation %s

What it means

When a JobID is supplied with an exec request, the handler verifies the target allocation actually belongs to that job. If args.JobID != alloc.JobID, it returns HTTP 400 with this message. It prevents exec'ing into an allocation that is unrelated to the job the client claims.

Solutions

  1. Fix the (jobID, allocID) pair so they match — derive the job ID from the alloc: `nomad alloc status <alloc-id>` shows Job ID.
  2. Omit JobID in the exec request; the API does not require it when an alloc ID is given.
  3. In scripts, look up the alloc's job dynamically instead of hardcoding.

Example fix

// before
exec({ allocID: a.ID, jobID: 'other-job' })
// after
exec({ allocID: a.ID, jobID: a.JobID }) // jobID from the same allocation
Defensive patterns

Strategy: validation

Validate before calling

const alloc = await nomad.alloc(allocID)
if (jobID && alloc.jobID !== jobID) {
  throw new Error(`alloc ${allocID} belongs to ${alloc.jobID}, not ${jobID}`)
}
return exec({ allocID, jobID: alloc.jobID, namespace: alloc.namespace })

Type guard

const belongsToJob = (alloc, jobID) => alloc.jobID === jobID

Try / catch

try { await exec({ allocID, jobID }) }
catch (e) {
  if (String(e).includes('does not have allocation')) {
    const a = await nomad.alloc(allocID)
    return exec({ allocID, jobID: a.jobID }) // correct the pairing and retry once
  }
  throw e
}

Prevention

When it happens

Trigger: Calling AllocExec with args.JobID set to job A while args.AllocID belongs to job B.

Common situations: Copying an alloc ID from a different job/deployment; automation pairing alloc IDs and job IDs from different sources; cluster with many similarly named jobs where the wrong alloc was selected.

Related errors


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

Appendix: source

Thrown at nomad/client_alloc_endpoint.go:570

	if args.JobID != "" {
		// Verify job exists.
		job, err := snap.JobByID(nil, args.Namespace, args.JobID)
		if err != nil {
			handleStreamResultError(err,
				new(int64(http.StatusInternalServerError)), encoder)
			return
		}
		if job == nil {
			handleStreamResultError(
				fmt.Errorf("job %s not found in namespace %s", args.JobID, args.Namespace),
				new(int64(http.StatusNotFound)), encoder)
			return
		}

		// Verify requested allocation belongs to the job.
		if args.JobID != alloc.JobID {
			handleStreamResultError(
				fmt.Errorf("job %s does not have allocation %s", args.JobID, alloc.ID),
				new(int64(http.StatusBadRequest)), encoder,
			)
		}
	}

	nodeID := alloc.NodeID

	// Make sure Node is valid and new enough to support RPC
	node, err := snap.NodeByID(nil, nodeID)
	if err != nil {
		handleStreamResultError(err, new(int64(500)), encoder)
		return
	}

	if node == nil {
		err := fmt.Errorf("Unknown node %q", nodeID)
		handleStreamResultError(err, new(int64(400)), encoder)
		return

View on GitHub (pinned to 482b49bf1a)