goreleaser/goreleaser · error

could not copy %q to %q: %w

Error message

could not copy %q to %q: %w

What it means

When multiple image repositories are configured (and not in snapshot mode), the image published to imageRepos[0] is copied to each additional repo via crane.Copy; failure is wrapped as "could not copy %q to %q". The source image exists but the copy/push to the destination failed.

Source

Thrown at internal/pipe/ko/ko.go:584

	if path == "" {
		return nil
	}
	if matched, _ := regexp.MatchString(`^\.?(\.\/[^\/]?.*)?$`, path); !matched {
		return errInvalidMainPath
	}
	// paths sure can have dots in them, but if the path ends in .go, it's probably a file that one misundertood as a valid value
	if strings.HasSuffix(path, ".go") {
		return errInvalidMainGoPath
	}
	return nil
}

func copyImage(src, dst string) (string, error) {
	log.WithField("src", src).
		WithField("dst", dst).
		Info("copying manifest")
	if err := crane.Copy(src, dst, crane.WithAuthFromKeychain(keychain)); err != nil {
		return "", fmt.Errorf("could not copy %q to %q: %w", src, dst, err)
	}
	digest, err := crane.Digest(dst, crane.WithAuthFromKeychain(keychain))
	if err != nil {
		return "", fmt.Errorf("could not get digest of %q: %w", dst, err)
	}
	return digest, nil
}

func makeArtifact(id, name, digest string) *artifact.Artifact {
	art := &artifact.Artifact{
		Type:  artifact.DockerManifest,
		Name:  name,
		Path:  name,
		Extra: map[string]any{},
	}
	if id != "" {
		art.Extra[artifact.ExtraID] = id
	}

View on GitHub (pinned to f5edd73956)

Solutions

  1. Read src/dst in the message and test `crane copy <src> <dst>` manually
  2. Authenticate to the additional registry (its keychain/credential helper entry)
  3. Create the destination repository or grant create permission
  4. Verify the destination repo name spelling and registry host

Example fix

// before
ko:
  repositories:
    - ghcr.io/owner/app
    - quay.io/wrong/app
// after
ko:
  repositories:
    - ghcr.io/owner/app
    - quay.io/owner/app
Defensive patterns

Strategy: retry

Validate before calling

for r in $(yq '.kos[].repositories[]' .goreleaser.yaml); do docker login "$(echo $r | cut -d/ -f1)" -u "$USER" -p "$TOKEN"; done

Try / catch

if err := doRelease(); err != nil {
    var cErr copyError
    if errors.As(err, &cErr) && isNetworkErr(err) {
        return retry(3, doRelease)
    }
    return err
}

Prevention

When it happens

Trigger: crane.Copy(src, dst, keychain auth) fails: destination repo doesn't exist / no create permission, auth missing for the additional registry, network failure, or unsupported destination.

Common situations: Second repo on a different registry with different credentials; typo in destination repo name; rate limits or quota on the target registry.

Related errors


AI-assisted analysis of goreleaser/goreleaser@f5edd73956 (2026-09-05). Data as JSON: /api/errors/067c98cd000f81bc. Report an issue: GitHub.