{"record":{"id":"21d744073286e8de","repo":"dagger/dagger","slug":"invalid-key-q-unescaped-control-character-in-quo","errorCode":null,"errorMessage":"invalid key %q: unescaped control character in quoted path segment","messagePattern":"invalid key %q: unescaped control character in quoted path segment","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/workspace/config.go","lineNumber":1093,"sourceCode":"\nfunc parseBasicConfigPathSegment(key string, start int) (string, int, error) {\n\tvar b strings.Builder\n\tfor i := start; i < len(key); {\n\t\tch := key[i]\n\t\ti++\n\t\tswitch ch {\n\t\tcase '\\\\':\n\t\t\tr, next, err := parseConfigPathEscape(key, i)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", 0, err\n\t\t\t}\n\t\t\tb.WriteRune(r)\n\t\t\ti = next\n\t\tcase '\"':\n\t\t\treturn b.String(), i, nil\n\t\tdefault:\n\t\t\tif ch < 0x20 || ch == 0x7f {\n\t\t\t\treturn \"\", 0, fmt.Errorf(\"invalid key %q: unescaped control character in quoted path segment\", key)\n\t\t\t}\n\t\t\tb.WriteByte(ch)\n\t\t}\n\t}\n\treturn \"\", 0, fmt.Errorf(\"invalid key %q: unterminated quoted path segment\", key)\n}\n\nfunc parseConfigPathEscape(key string, start int) (rune, int, error) {\n\tif start >= len(key) {\n\t\treturn 0, 0, fmt.Errorf(\"invalid key %q: trailing escape in quoted path segment\", key)\n\t}\n\n\tescaped := key[start]\n\tnext := start + 1\n\tswitch escaped {\n\tcase 'b':\n\t\treturn '\\b', next, nil\n\tcase 't':","sourceCodeStart":1075,"sourceCodeEnd":1111,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/core/workspace/config.go#L1075-L1111","documentation":"This error is thrown by the workspace config key parser (parseBasicConfigPathSegment) when a double-quoted path segment in a config key contains a raw control character (ASCII < 0x20 or DEL 0x7f) that is not expressed as an escape sequence such as \\t, \\n, or \\u00XX. The parser rejects raw control bytes to keep key strings unambiguous and printable.","triggerScenarios":"Calling the config-write API with a key like \"ignore\ted\" or \"my\\nkey.x\" where a double-quoted segment contains a literal tab, newline, or other control character instead of its backslash escape.","commonSituations":"Keys built by string concatenation or template interpolation that accidentally embed a newline or tab; copying a key from a JSON/YAML file where escapes were not carried over; pasting multi-line text into a key field.","solutions":["Replace the raw control character with its escape: use \\t, \\n, \\r, \\f, \\b, \\\" or \\\\ inside the quoted segment","Use a \\uXXXX (or \\UXXXXXXXX) escape for control characters without a short form","Remove the accidental control character if it was not intentional"],"exampleFix":"// before\nsetConfig(\"ignore\ted\", []string{\"*.log\"})\n// after\nsetConfig(\"ignore\\ted\", []string{\"*.log\"})","handlingStrategy":"validation","validationCode":"func hasRawControl(key string) bool {\n\tfor _, r := range key {\n\t\tif r < 0x20 || r == 0x7f {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n// before calling: if hasRawControl(key) { /* escape or reject */ }","typeGuard":"func isSafeConfigKey(key string) bool {\n\tfor _, r := range key {\n\t\tif r < 0x20 || r == 0x7f {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn key != \"\"\n}","tryCatchPattern":"if err := writeConfig(key, val); err != nil {\n\tif strings.Contains(err.Error(), \"unescaped control character\") {\n\t\t// re-escape key and retry once\n\t}\n\treturn err\n}","preventionTips":["Escape control characters as \\t \\n \\uXXXX when building keys","Never interpolate raw multi-line strings into config keys","Sanitize keys with a whitelist of allowed characters"],"tags":["config","parsing","escaping"],"backgroundTag":"invalid-config-key-syntax","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"}