kubernetes/kops · error

invalid image source URL %q: %w

Error message

invalid image source URL %q: %w

What it means

For each configured sideload image, Run() parses image.Sources[0] with net/url. If url.Parse fails, nodeup wraps the parse error as "invalid image source URL". This almost always means the first source string is not a syntactically valid URL (control characters, malformed scheme, etc.).

Source

Thrown at upup/pkg/fi/nodeup/command.go:350

	loader.Builders = append(loader.Builders, &networking.CalicoBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &networking.CiliumBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &networking.KindnetBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &networking.AmazonVPCRoutedENIBuilder{NodeupModelContext: modelContext})
	loader.Builders = append(loader.Builders, &networking.KuberouterBuilder{NodeupModelContext: modelContext})

	loader.Builders = append(loader.Builders, &model.BootstrapClientBuilder{NodeupModelContext: modelContext})
	taskMap, err := loader.Build()
	if err != nil {
		return fmt.Errorf("error building loader: %v", err)
	}

	for _, image := range nodeupConfig.Images[architecture] {
		if len(image.Sources) == 0 {
			return fmt.Errorf("image has no sources: %v", image)
		}
		u, err := url.Parse(image.Sources[0])
		if err != nil {
			return fmt.Errorf("invalid image source URL %q: %w", image.Sources[0], err)
		}
		key := "SideloadImage/" + path.Base(u.Path)
		if _, ok := taskMap[key]; ok {
			return fmt.Errorf("duplicate image task %q", key)
		}
		taskMap[key] = &nodetasks.LoadImageTask{
			Sources: image.Sources,
			Hash:    image.Hash,
		}
	}

	var target fi.NodeupTarget

	switch c.Target {
	case "direct":
		target = &local.LocalTarget{
			CacheDir: c.CacheDir,
			Cloud:    cloud,

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Look at the quoted URL in the error and fix the malformed source in the NodeupConfig / cluster spec
  2. Remove placeholder text or unescaped characters and re-render the config with `kops update cluster`
  3. Validate image source URLs with `url.Parse` semantics (e.g. quick check in Go or curl) before committing custom images
  4. Ensure the registry mirror/proxy URL used in the cluster spec is a valid absolute URL

Example fix

// before
// "sources": ["registry.example.com/{{ .cluster }}/pause:3.9"]
// after (rendered)
// "sources": ["registry.example.com/mycluster/pause:3.9"]
Defensive patterns

Strategy: validation

Validate before calling

if _, err := url.Parse(image.Sources[0]); err != nil {
    return fmt.Errorf("image %q source %q is not a valid URL", image.Name, image.Sources[0])
}

Type guard

func validImageSource(src string) bool {
    u, err := url.Parse(src)
    return err == nil && u.Scheme != "" && u.Host != ""
}

Try / catch

if err := nodeupCmd.Run(ctx); err != nil {
    if strings.Contains(err.Error(), "invalid image source URL") {
        var urlErr error
        errors.As(err, &urlErr)
        log.Fatalf("fix image source in cluster spec: %v", urlErr)
    }
    return err
}

Prevention

When it happens

Trigger: url.Parse(image.Sources[0]) returns an error for an entry in nodeupConfig.Images[architecture].

Common situations: Typo or unescaped characters in a custom image source; template substitution leaving placeholder text like {{ .registry }} in the URL; newline/whitespace corruption in generated nodeup config.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


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