GoogleContainerTools/skaffold · error

failed to clone repo %s: %w

Error message

failed to clone repo %s: %w

What it means

syncRepo starts by resolving the remote cache directory via config.GetRemoteCacheDir(opts). Note the result is assigned before the error check, so any error from GetRemoteCacheDir is wrapped with this 'failed to clone repo' message even though no cloning happened yet. The wrapped cause is whatever GetRemoteCacheDir returned.

Source

Thrown at pkg/skaffold/git/gitutil.go:103

}

// getRepoDir returns the cache directory name for a remote repo
func getRepoDir(g Config) (string, error) {
	inputs := []string{g.Repo, g.Ref}
	hasher := sha256.New()
	enc := json.NewEncoder(hasher)
	if err := enc.Encode(inputs); err != nil {
		return "", err
	}

	return base64.URLEncoding.EncodeToString(hasher.Sum(nil))[:32], nil
}

func syncRepo(ctx context.Context, g Config, opts config.SkaffoldOptions) (string, error) {
	skaffoldCacheDir, err := config.GetRemoteCacheDir(opts)
	r := gitCmd{Dir: skaffoldCacheDir}
	if err != nil {
		return "", fmt.Errorf("failed to clone repo %s: %w", g.Repo, err)
	}
	if err := os.MkdirAll(skaffoldCacheDir, 0700); err != nil {
		return "", fmt.Errorf(
			"failed to clone repo %s: trouble creating cache directory: %w", g.Repo, err)
	}

	ref := g.Ref
	if ref == "" {
		ref, err = defaultRef(ctx, g.RepoCloneURI, g.Repo)
		if err != nil {
			return "", fmt.Errorf("failed to clone repo %s: trouble getting default branch: %w", g.Repo, err)
		}
	}

	hash, err := getRepoDir(g)
	if err != nil {
		return "", fmt.Errorf("failed to clone git repo: unable to create directory name: %w", err)
	}

View on GitHub (pinned to a1189de023)

Solutions

  1. Inspect the wrapped cause (%w) printed below this message to see why GetRemoteCacheDir failed.
  2. Pass an explicit, valid cache path via --remote-cache-dir to bypass default resolution.
  3. Ensure SkaffoldOptions are fully populated when invoking SyncRepo programmatically (don't pass a zero-value struct).
  4. Check that the home/config directory used for the default cache path is resolvable (HOME set, config dir readable).

Example fix

// before
opts := config.SkaffoldOptions{}          // zero value; no cache dir
path, err := git.SyncRepo(ctx, cfg, opts)
// after
opts := config.SkaffoldOptions{RemoteCacheDir: "/tmp/skaffold-cache"}
path, err := git.SyncRepo(ctx, cfg, opts)
Defensive patterns

Strategy: validation

Validate before calling

if opts.RemoteCacheDir == "" {
    // let skaffold resolve the default, but ensure the environment supports it
    if os.Getenv("HOME") == "" {
        return errors.New("HOME not set; pass an explicit --remote-cache-dir")
    }
}

Type guard

func hasValidCacheDir(opts config.SkaffoldOptions) bool {
    if opts.RemoteCacheDir == "" {
        return true // default resolution applies; validate HOME instead
    }
    fi, err := os.Stat(filepath.Dir(opts.RemoteCacheDir))
    return err == nil && fi.IsDir()
}

Try / catch

path, err := git.SyncRepo(ctx, cfg, opts)
if err != nil {
    if strings.Contains(err.Error(), "failed to clone repo "+cfg.Repo) &&
        !strings.Contains(err.Error(), "trouble") && !strings.Contains(err.Error(), "git") {
        log.Warnf("cache dir resolution failed (no clone attempted): %v", err)
        return git.SyncRepo(ctx, cfg, config.SkaffoldOptions{RemoteCacheDir: fallbackDir})
    }
    return err
}

Prevention

When it happens

Trigger: Calling SyncRepo/syncRepo when config.GetRemoteCacheDir(opts) returns an error — i.e. skaffold cannot determine the remote cache directory from the provided SkaffoldOptions (e.g. the flag/config value is invalid or unavailable).

Common situations: Passing an invalid --remote-cache-dir value; calling the skaffold API/programmatic path with a zero-value or partially populated SkaffoldOptions; environment/config resolution failure for the default cache location.

Related errors


AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05). Data as JSON: /api/errors/276548ab321a6e39. Report an issue: GitHub.