{"record":{"id":"cbbd843412e374c1","repo":"hashicorp/nomad","slug":"consul-ingress-service-with-a-wildcard-service","errorCode":null,"errorMessage":"Consul Ingress Service with a wildcard \"*\" service name can not also specify hosts","messagePattern":"Consul Ingress Service with a wildcard \"\\*\" service name can not also specify hosts","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/services.go","lineNumber":2435,"sourceCode":"\t// pre-validate service Name and Hosts before passing along to consul:\n\t// https://developer.hashicorp.com/consul/docs/connect/config-entries/ingress-gateway#services\n\n\tif s.Name == \"\" {\n\t\treturn errors.New(\"Consul Ingress Service requires a name\")\n\t}\n\n\tswitch protocol {\n\tcase \"tcp\":\n\t\tif s.Name == \"*\" {\n\t\t\treturn errors.New(`Consul Ingress Service doesn't support wildcard name for \"tcp\" protocol`)\n\t\t}\n\n\t\tif len(s.Hosts) != 0 {\n\t\t\treturn errors.New(`Consul Ingress Service doesn't support associating hosts to a service for the \"tcp\" protocol`)\n\t\t}\n\tdefault:\n\t\tif s.Name == \"*\" && len(s.Hosts) != 0 {\n\t\t\treturn errors.New(`Consul Ingress Service with a wildcard \"*\" service name can not also specify hosts`)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ConsulIngressListener is used to configure a listener on a Consul Ingress\n// Gateway.\ntype ConsulIngressListener struct {\n\tPort     int\n\tProtocol string\n\tServices []*ConsulIngressService\n}\n\nfunc (l *ConsulIngressListener) Copy() *ConsulIngressListener {\n\tif l == nil {\n\t\treturn nil\n\t}","sourceCodeStart":2417,"sourceCodeEnd":2453,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/services.go#L2417-L2453","documentation":"For non-tcp (e.g. http) ingress protocols, Consul allows the wildcard name \"*\" OR explicit hosts, but not both: a wildcard catch-all cannot simultaneously be constrained to specific hosts. Nomad validates this combination in validateIngressService.","triggerScenarios":"An ingress service entry with name = \"*\" and a non-empty hosts list on a listener whose protocol is not \"tcp\".","commonSituations":"Trying to define a default catch-all route plus host overrides in one entry; template merging producing name=\"*\" while preserving hosts.","solutions":["Set an explicit service name if hosts are required","Keep name = \"*\" and remove the hosts block","Split into multiple service entries: one wildcard, one per named service with hosts"],"exampleFix":"// before\nservices {\n  name  = \"*\"\n  hosts = [\"app.example.com\"]\n}\n// after\nservices {\n  name  = \"app\"\n  hosts = [\"app.example.com\"]\n}","handlingStrategy":"validation","validationCode":"function validateWildcardWithHosts(s) {\n  if (s.name === \"*\" && (s.hosts ?? []).length > 0) {\n    throw new Error(\"wildcard '*' ingress service cannot also specify hosts\");\n  }\n}","typeGuard":"function isWildcardWithHosts(s) { return s.name === \"*\" && Array.isArray(s.hosts) && s.hosts.length > 0; }","tryCatchPattern":"try {\n  await nomad.jobs.validate(job);\n} catch (e) {\n  if (e.message.includes(\"can not also specify hosts\")) {\n    console.error(\"Split the wildcard entry from host-specific entries\");\n  } else throw e;\n}","preventionTips":["Model catch-all and host-specific routes as separate service entries","Assert that templates never merge name=\"*\" with inherited hosts","Add unit checks on generated gateway configs"],"tags":["nomad","consul","ingress-gateway","wildcard","hosts"],"backgroundTag":"invalid-config-combination","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"}