{"record":{"id":"7ae36b302cf45b40","repo":"dagger/dagger","slug":"illegal-exclusion-pattern","errorCode":null,"errorMessage":"illegal exclusion pattern: \"!\"","messagePattern":"illegal exclusion pattern: \"!\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/patternmatcher/patternmatcher.go","lineNumber":290,"sourceCode":"\tcleanedPattern string\n\tdirs           []string\n\tregexp         *regexp.Regexp\n\texclusion      bool\n}\n\nvar ErrEmptyPattern = errors.New(\"empty pattern\")\n\nfunc NewPattern(p string) (*Pattern, error) {\n\t// Eliminate leading and trailing whitespace.\n\tp = strings.TrimSpace(p)\n\tif p == \"\" {\n\t\treturn nil, ErrEmptyPattern\n\t}\n\tp = filepath.Clean(p)\n\tnewp := &Pattern{}\n\tif p[0] == '!' {\n\t\tif len(p) == 1 {\n\t\t\treturn nil, errors.New(\"illegal exclusion pattern: \\\"!\\\"\")\n\t\t}\n\t\tnewp.exclusion = true\n\t\tp = p[1:]\n\t}\n\t// Do some syntax checking on the pattern.\n\t// filepath's Match() has some really weird rules that are inconsistent\n\t// so instead of trying to dup their logic, just call Match() for its\n\t// error state and if there is an error in the pattern return it.\n\t// If this becomes an issue we can remove this since its really only\n\t// needed in the error (syntax) case - which isn't really critical.\n\tif _, err := filepath.Match(p, \".\"); err != nil {\n\t\treturn nil, err\n\t}\n\tnewp.cleanedPattern = p\n\tnewp.dirs = strings.Split(p, string(os.PathSeparator))\n\n\treturn newp, nil\n}","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/util/patternmatcher/patternmatcher.go#L272-L308","documentation":"After trimming and filepath.Clean, a pattern consisting solely of '!' would be an exclusion of nothing — meaningless and likely a typo. NewPattern detects this case and returns a dedicated error instead of constructing a Pattern that excludes nothing.","triggerScenarios":"Calling NewPattern(\"!\"), NewPattern(\" ! \"), or passing \"!\" as one of the patterns to New or Glob.","commonSituations":"A .dockerignore line containing just '!'; a script or template that interpolated an empty value after the '!' prefix (e.g. '!${EXCLUDE}') leaving a bare '!'; a user misunderstanding exclusion syntax.","solutions":["Remove the bare '!' line from the pattern list or ignore file","If you meant to exclude something, put a path after the '!', e.g. '!keep.txt'","Check template/variable expansion so the exclusion path isn't interpolated to empty","Filter out or validate patterns of length 1 before passing them to the matcher"],"exampleFix":"// before (.dockerignore)\n!\n// after\n!Dockerfile\n","handlingStrategy":"validation","validationCode":"func validExclusion(p string) bool {\n\tp = strings.TrimSpace(p)\n\treturn !(p == \"!\" || strings.TrimSpace(strings.TrimPrefix(p, \"!\")) == \"\")\n}","typeGuard":"func isBareExclusion(p string) bool { return strings.TrimSpace(p) == \"!\" }","tryCatchPattern":"p, err := NewPattern(raw)\nif err != nil && strings.Contains(err.Error(), \"illegal exclusion pattern\") {\n\t// skip or report the malformed '!' line\n}","preventionTips":["Never emit a '!' without a path after it in ignore files","Validate template-expanded patterns so exclusions never interpolate to empty","Test ignore-file parsing in CI to catch bare '!' lines"],"tags":["go","pattern-matching","ignore-files","exclusion"],"backgroundTag":"illegal-exclusion-pattern","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}