GoogleContainerTools/skaffold · error

invalid glob pattern: %w

Error message

invalid glob pattern: %w

What it means

expandSrcGlobPatterns expands each COPY source pattern with filepath.Glob; Go's Glob returns an ErrBadPattern for malformed patterns (the only realistic case is an unterminated character class like '['), and Skaffold wraps that as 'invalid glob pattern'. This is a caller-side path-pattern problem, not a Dockerfile syntax problem.

Source

Thrown at pkg/skaffold/docker/parse.go:224

	return nil
}

func expandSrcGlobPatterns(workspace string, cpCmds []*copyCommand) ([]FromTo, error) {
	var fts []FromTo
	for _, cpCmd := range cpCmds {
		matchesOne := false

		for _, p := range cpCmd.srcs {
			path := filepath.Join(workspace, p)
			if _, err := os.Stat(path); err == nil {
				fts = append(fts, FromTo{From: filepath.Clean(p), To: cpCmd.dest, ToIsDir: cpCmd.destIsDir, StartLine: cpCmd.startLine, EndLine: cpCmd.endLine})
				matchesOne = true
				continue
			}

			files, err := filepath.Glob(path)
			if err != nil {
				return nil, fmt.Errorf("invalid glob pattern: %w", err)
			}
			if files == nil {
				continue
			}

			for _, f := range files {
				rel, err := filepath.Rel(workspace, f)
				if err != nil {
					return nil, fmt.Errorf("getting relative path of %s", f)
				}

				fts = append(fts, FromTo{From: rel, To: cpCmd.dest, ToIsDir: cpCmd.destIsDir, StartLine: cpCmd.startLine, EndLine: cpCmd.endLine})
			}
			matchesOne = true
		}

		if !matchesOne {
			return nil, fmt.Errorf("file pattern %s must match at least one file", cpCmd.srcs)

View on GitHub (pinned to a1189de023)

Solutions

  1. Escape literal brackets in filenames, e.g. COPY app\[1\] /app, or rename the file to avoid brackets
  2. Balance the character class: app[12] is valid glob syntax
  3. Check the inner wrapped error — filepath.ErrBadPattern always means an unterminated '['
  4. Prefer passing literal paths without glob metacharacters when no pattern matching is needed

Example fix

// before (Dockerfile)
COPY build/app[1 /app
// after
COPY build/app\[1\] /app
Defensive patterns

Strategy: validation

Validate before calling

func patternsAreValidGlobs(srcs []string) error {
    for _, s := range srcs {
        if _, err := filepath.Glob(filepath.Join(workspace, s)); err != nil {
            return fmt.Errorf("COPY source %q is not a valid glob: %w", s, err)
        }
    }
    return nil
}
// cheap pre-check: unbalanced '['
func balancedBrackets(s string) bool { return strings.Count(s, "[") == strings.Count(s, "]") }

Type guard

func isValidGlobPattern(p string) bool {
    _, err := filepath.Glob(p)
    return err == nil
}

Try / catch

fts, err := skaffold.ReadCopyCmdsFromDockerfile(path, args, cfg, false)
if err != nil && strings.Contains(err.Error(), "invalid glob pattern") {
    return fmt.Errorf("escape literal '[' in COPY sources or balance the class: %w", err)
}

Prevention

When it happens

Trigger: A COPY/ADD source in the Dockerfile (after glob expansion against the workspace) contains an unbalanced '[' with no matching ']', e.g. COPY app[1 /app, reached via ReadCopyCmdsFromDockerfile.

Common situations: Filenames containing literal '[' bracket characters (common with generated/compiled artifacts) that were not escaped; someone writing regex-style patterns instead of glob syntax; accidental truncation of a pattern string.

Related errors


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