hashicorp/nomad · error

failed to parse source URL %q: %v

Error message

failed to parse source URL %q: %v

What it means

getURL parses the artifact's GetterSource with url.Parse; when parsing fails (err != nil) it wraps the underlying error in a non-recoverable *Error carrying the artifact URL. Nomad throws this because the artifact fetcher cannot even construct a request if the source URL is malformed — the getter subprocess can never be launched. Recoverable is false so the artifact download will not be retried.

Source

Thrown at client/allocrunner/taskrunner/getter/util.go:49

)

var ErrSandboxEscape = errors.New("artifact includes symlink that resolves outside of sandbox")

func getURL(taskEnv interfaces.EnvReplacer, artifact *structs.TaskArtifact) (string, error) {
	source := taskEnv.ReplaceEnv(artifact.GetterSource)

	// fixup GitHub SSH URL such as git@github.com:hashicorp/nomad.git
	gitSSH := false
	if strings.HasPrefix(source, githubPrefixSSH) {
		gitSSH = true
		source = source[len(githubPrefixSSH):]
	}

	u, err := url.Parse(source)
	if err != nil {
		return "", &Error{
			URL:         artifact.GetterSource,
			Err:         fmt.Errorf("failed to parse source URL %q: %v", artifact.GetterSource, err),
			Recoverable: false,
		}
	}

	// build the URL by substituting as necessary
	q := u.Query()
	for k, v := range artifact.GetterOptions {
		q.Set(k, taskEnv.ReplaceEnv(v))
	}
	u.RawQuery = q.Encode()

	// add the prefix back if necessary
	sourceURL := u.String()
	if gitSSH {
		sourceURL = fmt.Sprintf("%s%s", githubPrefixSSH, sourceURL)
	}

	return sourceURL, nil

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Print and inspect the exact artifact source value in the job file for hidden control characters or bad percent-escapes
  2. Rewrite the source as a clean, properly quoted URL string (e.g. quote the value in HCL: source = "https://...")
  3. If the source is templated, validate the expanded value (e.g. printf %q | URL-check) before submitting the job
  4. Use consul template or nomad job inspect to see the rendered job and confirm the final source URL

Example fix

// before
artifact {
  source = "https://example.com/artifact
v1.tar.gz"
}
// after
artifact {
  source = "https://example.com/artifact-v1.tar.gz"
}
Defensive patterns

Strategy: validation

Validate before calling

// validate artifact source before submitting the job
u, err := url.Parse(src)
if err != nil || src == "" {
    return fmt.Errorf("invalid artifact source %q: %v", src, err)
}

Try / catch

// on the client, this error is non-recoverable; catch in task-runner wrapper
if errors.Is(err, getterErrType) && !err.Recoverable {
    // do not retry; fix job spec
}

Prevention

When it happens

Trigger: url.Parse returns an error for the TaskArtifact.GetterSource — e.g. an unescaped control character or invalid percent-encoding in the source string (url.Parse rejects raw non-ASCII control bytes; note most syntactically odd strings still parse, so this fires mainly on control chars/bad escapes)

Common situations: Paste-in artifact sources with stray whitespace/newlines or CR characters from copy-paste, shell interpolation inserting control characters, mangled YAML/HCL quoting, or templated sources where a variable expanded to a string containing invalid byte sequences

Understand the failure class

Related errors


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