hashicorp/nomad · error
task.consul.partition %q must match group.consul.partition %
Error message
task.consul.partition %q must match group.consul.partition %q if both are set
What it means
Nomad supports Consul admin partitions (Consul Enterprise). When a job sets a partition at both the task-level `consul` block and the group-level `consul` block, they must be identical; otherwise the job fails validation. validateTaskPartitionMatchesGroup enforces this consistency to avoid ambiguous cluster/partition routing.
Source
Thrown at nomad/job_endpoint_hook_consul.go:29
// jobConsulHook is a job registration admission controller for Consul
// configuration in Consul, Service, and Template blocks
type jobConsulHook struct {
srv *Server
}
func (jobConsulHook) Name() string {
return "consul"
}
// validateTaskPartitionMatchesGroup validates that any partition set for the
// task.Consul matches any partition set for the group
func (jobConsulHook) validateTaskPartitionMatchesGroup(groupPartition string, taskConsul *structs.Consul) error {
if taskConsul.Partition == "" || groupPartition == "" {
return nil
}
if taskConsul.Partition != groupPartition {
return fmt.Errorf("task.consul.partition %q must match group.consul.partition %q if both are set", taskConsul.Partition, groupPartition)
}
return nil
}
// mutateImpl ensures that the job's Consul blocks have been configured with the
// correct Consul cluster if unset, and sets constraints on the Consul admin
// partition if set. This should be called by the Mutate method.
func (jobConsulHook) mutateImpl(job *structs.Job, defaultCluster string) *structs.Job {
for _, group := range job.TaskGroups {
if group.Consul != nil {
if group.Consul.Cluster == "" {
group.Consul.Cluster = defaultCluster
}
if group.Consul.Partition != "" {
group.Constraints = append(group.Constraints,
newConsulPartitionConstraint(group.Consul.Cluster, group.Consul.Partition))
}
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Set the task's `consul.partition` to the same value as the group's `consul.partition`.
- Remove the task-level `partition` field and rely on the group-level setting (or vice versa).
- Review which Consul partition the workload should join and align both blocks to it.
Example fix
// before
group "api" {
consul { partition = "prod" }
task "web" {
consul { partition = "staging" }
}
}
// after
group "api" {
consul { partition = "prod" }
task "web" {
consul { partition = "prod" }
}
} Defensive patterns
Strategy: validation
Validate before calling
function validatePartitionMatch(task, group) {
const tp = task.consul?.partition, gp = group.consul?.partition;
if (tp && gp && tp !== gp) {
throw new Error(`task.consul.partition "${tp}" must match group.consul.partition "${gp}"`);
}
} Type guard
function partitionsCompatible(taskConsul, groupConsul) { const tp = taskConsul?.partition || '', gp = groupConsul?.partition || ''; return !tp || !gp || tp === gp; } Prevention
- Set consul partition at only one level (prefer group-level) per job.
- When migrating consul blocks between task and group level, update partition fields together.
- Run `nomad job validate` in CI for jobs using Consul Enterprise partitions.
When it happens
Trigger: Submitting a job where `task { consul { partition = "foo" } }` differs from the enclosing `group { consul { partition = "bar" } }`; both must be non-empty and equal, otherwise the hook errors.
Common situations: Migrating from group-level to task-level consul configuration (or vice versa) and updating only one partition; copy-paste between jobs targeting different Consul partitions; teams with per-partition staging/production layouts misconfiguring one level.
Related errors
- non-default Consul cluster requires Nomad Enterprise
- tls_server_name may only be set for Consul service checks
- Service with provider nomad cannot include Connect blocks
- Consul Ingress Service requires a name
- Task group service validation failed: %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/26a246dcaba24c26.
Report an issue: GitHub.