kubernetes/kops · error

unable to parse asset URL %q: %w

Error message

unable to parse asset URL %q: %w

What it means

buildFileAsset parses the canonical containerd-family asset URL with url.Parse before remapping. A malformed canonicalURL (from containerd/nerdctl/runc config) fails here and is wrapped with %w so the underlying parse error is preserved. It is the containerd-package equivalent of the CNI URL parse guard.

Source

Thrown at pkg/nodemodel/wellknownassets/containerd.go:98

	}

	var u string
	switch arch {
	case architectures.ArchitectureAmd64:
		u = fmt.Sprintf(containerdReleaseUrlAmd64, version, version)
	case architectures.ArchitectureArm64:
		u = fmt.Sprintf(containerdReleaseUrlArm64, version, version)
	default:
		return nil, fmt.Errorf("unknown arch: %q", arch)
	}

	return url.Parse(u)
}

func buildFileAsset(assetBuilder *assets.AssetBuilder, canonicalURL string, knownHashString string) (*assets.FileAsset, error) {
	u, err := url.Parse(canonicalURL)
	if err != nil {
		return nil, fmt.Errorf("unable to parse asset URL %q: %w", canonicalURL, err)
	}

	var knownHash *hashing.Hash
	if knownHashString != "" {
		h, err := hashing.FromString(knownHashString)
		if err != nil {
			return nil, fmt.Errorf("unable to parse asset hash %q: %w", knownHashString, err)
		}
		knownHash = h
	}

	asset, err := assetBuilder.RemapFile(u, knownHash)
	if err != nil {
		return nil, fmt.Errorf("unable to remap asset: %w", err)
	}

	return asset, nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Inspect the wrapped error for the exact position/syntax problem and correct the canonical URL in the cluster spec
  2. URL-encode special characters (spaces -> %20) in configured asset URLs
  3. Validate the configured URL with url.Parse or a validator before applying the cluster spec
  4. If using containerd.packages, point the URL fields at valid https tarball URLs

Example fix

// before
url: "https://github.com/containerd/containerd/releases/download/v2.1.0/containerd 2.1.0.tar.gz"
// after
url: "https://github.com/containerd/containerd/releases/download/v2.1.0/containerd-2.1.0-linux-amd64.tar.gz"
Defensive patterns

Strategy: validation

Validate before calling

if _, err := url.Parse(canonicalURL); err != nil {
    return fmt.Errorf("containerd asset URL %q is invalid: %v", canonicalURL, err)
}

Try / catch

asset, err := wellknownassets.FindContainerdAsset(ig, assetBuilder, arch)
if err != nil && strings.Contains(err.Error(), "unable to parse asset URL") {
    return fmt.Errorf("fix the configured containerd asset URL: %w", err)
}

Prevention

When it happens

Trigger: FindContainerdAsset, FindNerdctlAsset, or FindRuncAsset pass a canonicalURL (often built from containerd.packages or custom URL settings) that url.Parse rejects — e.g. containing spaces, control characters, or a scheme-less malformed string.

Common situations: Custom package URLs in the cluster spec with typos or unencoded spaces; template expansion errors producing empty/garbled URLs; pasting URLs with surrounding quotes or trailing punctuation.

Understand the failure class

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/2013c608060b7a5a. Report an issue: GitHub.