{"record":{"id":"0c3bce2297680d1c","repo":"slimtoolkit/slim","slug":"invalid-escape-s-must-be-or","errorCode":null,"errorMessage":"invalid ESCAPE '%s'. Must be ` or \\","messagePattern":"invalid ESCAPE '(.+?)'\\. Must be ` or \\\\","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/docker/dockerfile/ast/parser.go","lineNumber":146,"sourceCode":"\ttokenComment       = regexp.MustCompile(`^#.*$`)\n)\n\n// DefaultEscapeToken is the default escape token\nconst DefaultEscapeToken = '\\\\'\n\n// Directive is the structure used during a build run to hold the state of\n// parsing directives.\ntype Directive struct {\n\tescapeToken           rune           // Current escape token\n\tlineContinuationRegex *regexp.Regexp // Current line continuation regex\n\tprocessingComplete    bool           // Whether we are done looking for directives\n\tescapeSeen            bool           // Whether the escape directive has been seen\n}\n\n// setEscapeToken sets the default token for escaping characters in a Dockerfile.\nfunc (d *Directive) setEscapeToken(s string) error {\n\tif s != \"`\" && s != \"\\\\\" {\n\t\treturn fmt.Errorf(\"invalid ESCAPE '%s'. Must be ` or \\\\\", s)\n\t}\n\td.escapeToken = rune(s[0])\n\td.lineContinuationRegex = regexp.MustCompile(`\\` + s + `[ \\t]*$`)\n\treturn nil\n}\n\n// possibleParserDirective looks for parser directives, eg '# escapeToken=<char>'.\n// Parser directives must precede any builder instruction or other comments,\n// and cannot be repeated.\nfunc (d *Directive) possibleParserDirective(line string) error {\n\tif d.processingComplete {\n\t\treturn nil\n\t}\n\n\ttecMatch := tokenEscapeCommand.FindStringSubmatch(strings.ToLower(line))\n\tif len(tecMatch) != 0 {\n\t\tfor i, n := range tokenEscapeCommand.SubexpNames() {\n\t\t\tif n == \"escapechar\" {","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/slimtoolkit/slim/blob/81940d17fa112cc678e32209214bcb2355cb3004/pkg/docker/dockerfile/ast/parser.go#L128-L164","documentation":"The Dockerfile parser's setEscapeToken validates the value of a parser-directive ESCAPE (# escape=` or # escape=\\). Only the backtick and backslash are legal escape tokens (matching Docker's spec); any other character makes the parser return this error. The escape token controls line-continuation and character escaping during parsing.","triggerScenarios":"Parsing a Dockerfile containing a directive like `# escape='` or `# escape=x` with an unsupported character, or a malformed escape directive line whose extracted value isn't exactly ` or \\.","commonSituations":"Copy-pasted Dockerfiles with a typo'd escape directive; editors converting backticks/backslashes; using `# escape=\"` thinking quotes are allowed; confusion with the case-sensitive directive name/value.","solutions":["Change the directive to a legal value: `# escape=\\` (default) or `# escape=\\`` (backtick, useful on Windows).","Remove the escape directive entirely if you don't need a custom escape token.","Fix typos/case: the directive must be `# escape=<char>` with exactly one legal character and no quotes.","Re-run the build/parser after fixing; the error names the offending character in %s."],"exampleFix":"# before\n# escape=\"\nFROM ubuntu\n# after\n# escape=`\nFROM ubuntu","handlingStrategy":"validation","validationCode":"re := regexp.MustCompile(`(?m)^#\\s*escape\\s*=\\s*(.)\\s*$`)\nif m := re.FindStringSubmatch(dockerfile); m != nil && m[1] != \"`\" && m[1] != \"\\\\\" {\n    return fmt.Errorf(\"invalid escape directive %q; use ` or \\\\\", m[1])\n}","typeGuard":null,"tryCatchPattern":"err := parser.Parse(strings.NewReader(dockerfile))\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid ESCAPE\") {\n        dockerfile = fixEscapeDirective(dockerfile) // rewrite to `# escape=\\`\n        err = parser.Parse(strings.NewReader(dockerfile))\n    }\n    return err\n}","preventionTips":["Only use `# escape=\\` or `# escape=`` in Dockerfiles.","Never quote the escape value; it must be a single unquoted character.","Lint Dockerfiles with hadolint or a parse preflight in CI.","Watch editor auto-substitutions that replace backslashes/backticks with lookalikes."],"tags":["go","dockerfile","parser","validation"],"backgroundTag":"invalid-escape-directive","analyzedSha":"81940d17fa112cc678e32209214bcb2355cb3004","analyzedAt":"2026-08-31T23:06:12.682Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}