{"record":{"id":"ed0a1d1e750dea33","repo":"GoogleContainerTools/skaffold","slug":"invalid-glob-pattern-w","errorCode":null,"errorMessage":"invalid glob pattern: %w","messagePattern":"invalid glob pattern: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/skaffold/docker/parse.go","lineNumber":224,"sourceCode":"\treturn nil\n}\n\nfunc expandSrcGlobPatterns(workspace string, cpCmds []*copyCommand) ([]FromTo, error) {\n\tvar fts []FromTo\n\tfor _, cpCmd := range cpCmds {\n\t\tmatchesOne := false\n\n\t\tfor _, p := range cpCmd.srcs {\n\t\t\tpath := filepath.Join(workspace, p)\n\t\t\tif _, err := os.Stat(path); err == nil {\n\t\t\t\tfts = append(fts, FromTo{From: filepath.Clean(p), To: cpCmd.dest, ToIsDir: cpCmd.destIsDir, StartLine: cpCmd.startLine, EndLine: cpCmd.endLine})\n\t\t\t\tmatchesOne = true\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfiles, err := filepath.Glob(path)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid glob pattern: %w\", err)\n\t\t\t}\n\t\t\tif files == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfor _, f := range files {\n\t\t\t\trel, err := filepath.Rel(workspace, f)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"getting relative path of %s\", f)\n\t\t\t\t}\n\n\t\t\t\tfts = append(fts, FromTo{From: rel, To: cpCmd.dest, ToIsDir: cpCmd.destIsDir, StartLine: cpCmd.startLine, EndLine: cpCmd.endLine})\n\t\t\t}\n\t\t\tmatchesOne = true\n\t\t}\n\n\t\tif !matchesOne {\n\t\t\treturn nil, fmt.Errorf(\"file pattern %s must match at least one file\", cpCmd.srcs)","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/docker/parse.go#L206-L242","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Escape literal brackets in filenames, e.g. COPY app\\[1\\] /app, or rename the file to avoid brackets","Balance the character class: app[12] is valid glob syntax","Check the inner wrapped error — filepath.ErrBadPattern always means an unterminated '['","Prefer passing literal paths without glob metacharacters when no pattern matching is needed"],"exampleFix":"// before (Dockerfile)\nCOPY build/app[1 /app\n// after\nCOPY build/app\\[1\\] /app","handlingStrategy":"validation","validationCode":"func patternsAreValidGlobs(srcs []string) error {\n    for _, s := range srcs {\n        if _, err := filepath.Glob(filepath.Join(workspace, s)); err != nil {\n            return fmt.Errorf(\"COPY source %q is not a valid glob: %w\", s, err)\n        }\n    }\n    return nil\n}\n// cheap pre-check: unbalanced '['\nfunc balancedBrackets(s string) bool { return strings.Count(s, \"[\") == strings.Count(s, \"]\") }","typeGuard":"func isValidGlobPattern(p string) bool {\n    _, err := filepath.Glob(p)\n    return err == nil\n}","tryCatchPattern":"fts, err := skaffold.ReadCopyCmdsFromDockerfile(path, args, cfg, false)\nif err != nil && strings.Contains(err.Error(), \"invalid glob pattern\") {\n    return fmt.Errorf(\"escape literal '[' in COPY sources or balance the class: %w\", err)\n}","preventionTips":["Escape '[' and ']' in filenames that contain them literally","Prefer explicit paths over globs when matching is not needed","Add a CI check that runs filepath.Glob on every COPY source extracted from your Dockerfiles","Avoid regex-style patterns — Dockerfile COPY sources are Go globs, not regex"],"tags":["glob","filepath","dockerfile-copy"],"backgroundTag":"dockerfile-copy-source-not-found","analyzedSha":"a1189de023efc32d4b8e11f395acc678aa555011","analyzedAt":"2026-09-05T12:09:27.064Z","contentChangedAt":"2026-09-05T12:09:27.064Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}