{"record":{"id":"5ecb898969bee8da","repo":"hashicorp/nomad","slug":"service-q-cannot-use-address-mode-alloc-only-s","errorCode":null,"errorMessage":"service %q cannot use address_mode=\"alloc\", only services defined in a \"group\" block can use this mode","messagePattern":"service %q cannot use address_mode=\"alloc\", only services defined in a \"group\" block can use this mode","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/structs.go","lineNumber":8486,"sourceCode":"\n\t// Ensure that services don't ask for nonexistent ports and their names are\n\t// unique.\n\tservicePorts := make(map[string]map[string]struct{})\n\taddServicePort := func(label, service string) {\n\t\tif _, ok := servicePorts[label]; !ok {\n\t\t\tservicePorts[label] = map[string]struct{}{}\n\t\t}\n\t\tservicePorts[label][service] = struct{}{}\n\t}\n\tknownServices := make(map[string]struct{})\n\tfor i, service := range t.Services {\n\t\tif err := service.Validate(); err != nil {\n\t\t\touter := fmt.Errorf(\"service[%d] %+q validation failed: %s\", i, service.Name, err)\n\t\t\tmErr.Errors = append(mErr.Errors, outer)\n\t\t}\n\n\t\tif service.AddressMode == AddressModeAlloc {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"service %q cannot use address_mode=\\\"alloc\\\", only services defined in a \\\"group\\\" block can use this mode\", service.Name))\n\t\t}\n\n\t\tif service.AddressMode == AddressModeAllocIPv6 {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"service %q cannot use address_mode=\\\"alloc_ipv6\\\", only services defined in a \\\"group\\\" block can use this mode\", service.Name))\n\t\t}\n\n\t\t// Ensure that services with the same name are not being registered for\n\t\t// the same port\n\t\tif _, ok := knownServices[service.Name+service.PortLabel]; ok {\n\t\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"service %q is duplicate\", service.Name))\n\t\t}\n\t\tknownServices[service.Name+service.PortLabel] = struct{}{}\n\n\t\tif service.PortLabel != \"\" {\n\t\t\tif service.AddressMode == \"driver\" {\n\t\t\t\t// Numeric port labels are valid for address_mode=driver\n\t\t\t\t_, err := strconv.Atoi(service.PortLabel)\n\t\t\t\tif err != nil {","sourceCodeStart":8468,"sourceCodeEnd":8504,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/structs.go#L8468-L8504","documentation":"Nomad's job validation (validateServices for a task group) rejects address_mode=\"alloc\" on services that are not defined directly in a \"group\" block. The alloc address mode uses the allocation's own address, which is only meaningful at group level; task-level services must resolve addresses via the driver or a port label. This error is accumulated into a MultiError during job submission (`nomad job run` / Job.Register).","triggerScenarios":"Submitting a job where a `service` block nested inside a `task` (or inside a task within a group) sets `address_mode = \"alloc\"`. The check runs when service.AddressMode == structs.AddressModeAlloc during group service validation.","commonSituations":"Copy-pasting a group-level service stanza into a task stanza without removing address_mode=\"alloc\"; upgrading jobs from older Nomad versions where address modes behaved differently; confusing group-level vs task-level service semantics in job HCL/JSON.","solutions":["Remove `address_mode = \"alloc\"` from the task-level service block, or delete the line to use the default driver-based address mode.","Move the service block up to the `group` level if you genuinely need allocation-wide addressing.","Use `address_mode = \"driver\"` (default) or \"host\" with a proper port_label on the task-level service.","Validate the job locally with `nomad job validate <file>` before submission to catch it early."],"exampleFix":"// before (task-level service)\ntask \"web\" {\n  service {\n    name = \"api\"\n    port = \"http\"\n    address_mode = \"alloc\"\n  }\n}\n\n// after\ntask \"web\" {\n  service {\n    name = \"api\"\n    port = \"http\"\n    # address_mode removed (defaults to \"driver\")\n  }\n}","handlingStrategy":"validation","validationCode":"// Pre-validate job HCL/JSON before submission:\n// for each task-level service, ensure address_mode != \"alloc\"\nfor _, tg := range job.TaskGroups {\n  for _, t := range tg.Tasks {\n    for _, s := range t.Services {\n      if s.AddressMode == \"alloc\" {\n        return fmt.Errorf(\"task %s: service %q cannot use address_mode=alloc at task level\", t.Name, s.Name)\n      }\n    }\n  }\n}\n// or simply: nomad job validate job.hcl","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only set address_mode on group-level service blocks","Run `nomad job validate` in CI before every job submit","Omit address_mode and let Nomad default to \"driver\" unless alloc addressing is required"],"tags":["nomad","service-validation","address-mode","job-spec"],"backgroundTag":"invalid-service-address-mode","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}