kubernetes/kops · error
duplicate image task %q
Error message
duplicate image task %q
What it means
Run() keys each sideload image task as "SideloadImage/" + the base name of the source URL path. If a task with that key already exists in the taskMap, nodeup refuses to overwrite it and errors with "duplicate image task". This prevents two LoadImageTasks fighting over the same image file, usually caused by duplicate image entries in the config.
Source
Thrown at upup/pkg/fi/nodeup/command.go:354
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,
}
case "dryrun":
assetBuilder := assets.NewAssetBuilder(vfs.Context, nil, false)
target = fi.NewNodeupDryRunTarget(assetBuilder, out)View on GitHub (pinned to 4c8573c808)
Solutions
- De-duplicate the image list in nodeupConfig.Images[architecture] so each source filename appears once
- If a mirror variant is needed, rename the path segment so base(u.Path) differs (e.g. include a subdirectory or distinct filename)
- Regenerate the config with `kops update cluster` after cleaning up custom image overrides in the cluster spec
- Check that any config merge/patch tooling is not appending the same image twice
Example fix
// before: two entries whose sources both end in /pause:3.9 -> SideloadImage/pause:3.9 twice // after: keep one entry or differentiate paths // "sources": ["https://registry.k8s.io/pause:3.9"] // remove the duplicate mirror entry
Defensive patterns
Strategy: validation
Validate before calling
seen := map[string]bool{}
for _, img := range nodeupConfig.Images[arch] {
u, _ := url.Parse(img.Sources[0])
key := "SideloadImage/" + path.Base(u.Path)
if seen[key] {
return fmt.Errorf("duplicate image %s in config", key)
}
seen[key] = true
} Try / catch
if err := nodeupCmd.Run(ctx); err != nil {
if strings.Contains(err.Error(), "duplicate image task") {
log.Fatalf("de-duplicate images in NodeupConfig: %v", err)
}
return err
} Prevention
- De-duplicate image lists when merging or patching cluster specs
- Give mirror copies distinct path segments if both are needed
- Run `kops update cluster --target dryrun` and review the rendered images map
- Automate a pre-flight dup check on custom image overrides
When it happens
Trigger: Two or more entries in nodeupConfig.Images[architecture] whose first source URL has the same path base (e.g. same filename from different registries), producing the same SideloadImage/<name> key.
Common situations: The same image listed twice (once from registry.k8s.io, once from a mirror) in containerd images config; merging cluster specs that duplicated an image entry; case/name collisions between custom and default images.
Related errors
- error building loader: %v
- image has no sources: %v
- invalid image source URL %q: %w
- building nodeConfig for instanceGroup: %w
- marshalling nodeupConfig: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/504af5d91646f42c.
Report an issue: GitHub.