hashicorp/nomad · error

Failed to pull `%s`: %w

Error message

Failed to pull `%s`: %w

What it means

recoverablePullError wraps any error from the Docker image pull as "Failed to pull `<image>`", marking it recoverable unless the error text matches the imageNotFoundMatcher (e.g. manifest unknown / not found), in which case retrying is pointless. Callers use the recoverable flag to decide whether to reschedule the allocation.

Source

Thrown at drivers/docker/coordinator.go:429

func (d *dockerCoordinator) handlePullProgressReport(image, msg string, _ time.Time) {
	d.logger.Debug("image pull progress", "image_name", image, "message", msg)
}

func (d *dockerCoordinator) handleSlowPullProgressReport(image, msg string, _ time.Time) {
	d.emitEvent(image, fmt.Sprintf("Docker image pull progress: %s", msg), map[string]string{
		"image": image,
	})
}

// recoverablePullError wraps the error gotten when trying to pull and image if
// the error is recoverable.
func recoverablePullError(err error, image string) error {
	recoverable := true
	if imageNotFoundMatcher.MatchString(err.Error()) {
		recoverable = false
	}
	return structs.NewRecoverableError(fmt.Errorf("Failed to pull `%s`: %w", image, err), recoverable)
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Read the wrapped cause: if 'not found'/'manifest unknown', fix the image name/tag — retrying will not help.
  2. If recoverable (network/rate limit), configure registry auth (auth block or docker config) and check registry connectivity.
  3. Add registry credentials for private repos or authenticated Hub pulls to avoid rate limits.
  4. Verify DNS/proxy/firewall allows the node to reach the registry endpoint.
  5. Retry later for transient 5xx/timeout causes; Nomad will reschedule recoverable failures.

Example fix

// before (job HCL, private registry)
config { image = "mycorp/app:latest" }
// after
config { image = "mycorp/app:1.4.2" }
auth {
  username = "ci-user"
  password = "..."
  server_address = "https://registry.mycorp.example"
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check image exists before submit
cli, _ := client.NewClientWithOpts(client.FromEnv)
if _, err := cli.DistributionInspect(ctx, image, authToken); err != nil {
    return fmt.Errorf("image %q not resolvable in registry: %w", image, err)
}

Type guard

func isNonRecoverablePull(err error) bool {
    var re *structs.RecoverableError
    if errors.As(err, &re) { return !re.IsRecoverable() }
    return false
}

Try / catch

err := pull(...)
var re *structs.RecoverableError
if errors.As(err, &re) && !re.IsRecoverable() {
    return fmt.Errorf("bad image name/tag, not retrying: %w", err)
}
// otherwise backoff + retry

Prevention

When it happens

Trigger: Any pullImageImpl failure reaching this wrapper: registry unreachable, auth rejected, rate limited, network timeouts, or image truly nonexistent in the registry.

Common situations: Docker Hub rate limiting (429 toomanyrequests), missing/misconfigured registry auth for a private repo, wrong image name (typo causing 'not found' -> non-recoverable), corporate proxy blocking registry.default

Related errors


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