{"record":{"id":"9de885e9a6db63b1","repo":"hashicorp/nomad","slug":"error-interpreting-desired-envoy-version-from-cons","errorCode":null,"errorMessage":"error interpreting desired Envoy version from Consul: %w","messagePattern":"error interpreting desired Envoy version from Consul: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocrunner/taskrunner/envoy_version_hook.go","lineNumber":97,"sourceCode":"\t\treturn nil\n\t}\n\n\t// We either need to acquire Consul's preferred Envoy version or fallback\n\t// to the legacy default. Query Consul and use the (possibly empty) result.\n\t//\n\t// TODO(tgross): how do we select the right cluster here if we have multiple\n\t// services which could have their own cluster field value?\n\tproxies, err := h.proxiesClientFunc(structs.ConsulDefaultCluster).Proxies()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error retrieving supported Envoy versions from Consul: %w\", err)\n\t}\n\n\t// Second [pseudo] interpolation of task image. This determines the concrete\n\t// Envoy image identifier by applying version string substitution of\n\t// ${NOMAD_envoy_version} acquired from Consul.\n\timage, err := h.tweakImage(h.taskImage(request.Task.Config), proxies)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error interpreting desired Envoy version from Consul: %w\", err)\n\t}\n\n\t// Set the resulting image.\n\th.logger.Trace(\"setting task envoy image\", \"image\", image)\n\trequest.Task.Config[\"image\"] = image\n\treturn nil\n}\n\n// interpolateImage applies the first pass of interpolation on the task's\n// config.image value. This is where ${meta.connect.sidecar_image} or\n// ${meta.connect.gateway_image} becomes something that might include the\n// ${NOMAD_envoy_version} pseudo variable for further resolution.\nfunc (_ *envoyVersionHook) interpolateImage(task *structs.Task, env *taskenv.TaskEnv) {\n\tvalue, exists := task.Config[\"image\"]\n\tif !exists {\n\t\treturn\n\t}\n","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocrunner/taskrunner/envoy_version_hook.go#L79-L115","documentation":"After fetching the supported proxies data from Consul, the hook calls tweakImage to interpolate ${NOMAD_envoy_version} in the task's configured Envoy image. If tweakImage fails (it internally runs the semver parsing), the hook wraps the error meaning Nomad could not interpret the Envoy version Consul reported.","triggerScenarios":"h.tweakImage(h.taskImage(request.Task.Config), proxies) returns an error in Prestart — typically because the version string returned by Consul (or derived from the image) isn't parseable as semver, e.g. it is empty, has an unexpected format, or the image template is malformed.","commonSituations":"Consul returns a version string the hook can't parse (unusual or missing version); job image field uses ${NOMAD_envoy_version} in a way that leaves an invalid version after interpolation; unofficial Envoy image tags not matching x.y.z; Consul/nomad version mismatch producing unexpected proxy data.","solutions":["Inspect the wrapped %v detail to see the exact parse failure and the offending version string.","Set an explicit envoy version-supported config or pin the task image instead of relying on ${NOMAD_envoy_version}.","Ensure the Consul version reports a standard x.y.z Envoy version; upgrade Consul if it returns unexpected data.","Use an official envoy version tag format (vX.Y.Z or X.Y.Z) in your image template.","Check nomad/consul version compatibility for the connect/envoy version negotiation feature."],"exampleFix":"// before\nimage = \"envoyproxy/envoy:v${NOMAD_envoy_version}\" // yields v:1.28.0-ish parse quirks or empty version\n// after\nimage = \"envoyproxy/envoy:${NOMAD_envoy_version}\" // or pin: \"envoyproxy/envoy:v1.28.0\"","handlingStrategy":"validation","validationCode":"import \"github.com/hashicorp/go-version\"\n// validate the image template yields a parseable version before submit\nv, err := version.NewVersion(\"1.28.0\") // value Consul is expected to report\nif err != nil { return fmt.Errorf(\"bad envoy version: %w\", err) }","typeGuard":"func isParseableEnvoyVersion(s string) bool {\n    _, err := version.NewVersion(strings.TrimPrefix(s, \"v\"))\n    return err == nil\n}","tryCatchPattern":"err := hook.Prestart(ctx, req)\nif err != nil && strings.HasPrefix(err.Error(), \"error interpreting desired Envoy version\") {\n    // pin an explicit envoy image in the task config and resubmit\n}","preventionTips":["Pin an explicit Envoy image instead of relying on ${NOMAD_envoy_version} when unsure.","Use official, semver-formatted Envoy tags (X.Y.Z or vX.Y.Z).","Keep Consul and Nomad versions aligned for connect version negotiation.","Test job image templates locally to confirm interpolation produces a valid version."],"tags":["nomad","consul","envoy","semver","interpolation"],"backgroundTag":"unexpected-envoy-version-format","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"}