hashicorp/nomad · error

unexpected envoy version format: %w

Error message

unexpected envoy version format: %w

What it means

The semver helper normalizes the chosen Envoy version string using hashicorp/go-version. Version strings without a leading 'v' and unofficial 3-number tags are tolerated by design, but if version.NewVersion(chosen) fails outright, the version format is unrecognized and this error is returned (later wrapped by tweakImage callers).

Source

Thrown at client/allocrunner/taskrunner/envoy_version_hook.go:196

	latest, err := semver(versions[0])
	if err != nil {
		return "", err
	}

	return strings.ReplaceAll(configured, envoy.VersionVar, latest), nil
}

// semver sanitizes the envoy version string coming from Consul into the format
// used by the Envoy project when publishing images (i.e. proper semver). This
// resulting string value does NOT contain the 'v' prefix for 2 reasons:
//  1. the version library does not include the 'v'
//  2. its plausible unofficial images use the 3 numbers without the prefix for
//     tagging their own images
func semver(chosen string) (string, error) {
	v, err := version.NewVersion(chosen)
	if err != nil {
		return "", fmt.Errorf("unexpected envoy version format: %w", err)
	}
	return v.String(), nil
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check the wrapped error text to see the offending version string from Consul.
  2. Set an explicit, semver-parsable image (e.g. envoyproxy/envoy:v1.28.0) so the hook doesn't need to interpolate.
  3. Upgrade Nomad (and/or Consul) if the reported version uses a format your Nomad version can't parse.
  4. If running unofficial Envoy images, tag them as plain x.y.z (three numbers, optional 'v' prefix).

Example fix

// before
image: "envoyproxy/envoy:latest"
// after
image: "envoyproxy/envoy:v1.28.0"
Defensive patterns

Strategy: type-guard

Validate before calling

import "github.com/hashicorp/go-version"
// validate any custom envoy version string before using it in an image
if _, err := version.NewVersion(strings.TrimPrefix(chosen, "v")); err != nil {
    return fmt.Errorf("invalid envoy version %q", chosen)
}

Type guard

func isEnvoySemver(s string) bool {
    _, err := version.NewVersion(strings.TrimPrefix(s, "v"))
    return err == nil
}

Try / catch

image, err := tweakImage(taskImage, proxies)
if err != nil {
    var verErr error
    if errors.As(err, &verErr) && strings.Contains(err.Error(), "unexpected envoy version format") {
        image = fallbackEnvoyImage // e.g. envoyproxy/envoy:v1.28.0
    }
}

Prevention

When it happens

Trigger: version.NewVersion(chosen) errors inside semver — chosen is empty, contains non-numeric/prerelease garbage, or a string like 'latest'/'stable' instead of a version like '1.28.0' or 'v1.28.0'.

Common situations: Consul reporting an unexpected or empty Envoy version; job image template interpolating to 'latest' or a digest; custom/enterprise Envoy image tags that aren't numeric versions; regression from Consul returning a new version scheme the Nomad version doesn't parse.

Related errors


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