dagger/dagger · error

invalid key %q: unescaped control character in quoted path s

Error message

invalid key %q: unescaped control character in quoted path segment

What it means

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.

Source

Thrown at core/workspace/config.go:1093

func parseBasicConfigPathSegment(key string, start int) (string, int, error) {
	var b strings.Builder
	for i := start; i < len(key); {
		ch := key[i]
		i++
		switch ch {
		case '\\':
			r, next, err := parseConfigPathEscape(key, i)
			if err != nil {
				return "", 0, err
			}
			b.WriteRune(r)
			i = next
		case '"':
			return b.String(), i, nil
		default:
			if ch < 0x20 || ch == 0x7f {
				return "", 0, fmt.Errorf("invalid key %q: unescaped control character in quoted path segment", key)
			}
			b.WriteByte(ch)
		}
	}
	return "", 0, fmt.Errorf("invalid key %q: unterminated quoted path segment", key)
}

func parseConfigPathEscape(key string, start int) (rune, int, error) {
	if start >= len(key) {
		return 0, 0, fmt.Errorf("invalid key %q: trailing escape in quoted path segment", key)
	}

	escaped := key[start]
	next := start + 1
	switch escaped {
	case 'b':
		return '\b', next, nil
	case 't':

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Replace the raw control character with its escape: use \t, \n, \r, \f, \b, \" or \\ inside the quoted segment
  2. Use a \uXXXX (or \UXXXXXXXX) escape for control characters without a short form
  3. Remove the accidental control character if it was not intentional

Example fix

// before
setConfig("ignore	ed", []string{"*.log"})
// after
setConfig("ignore\ted", []string{"*.log"})
Defensive patterns

Strategy: validation

Validate before calling

func hasRawControl(key string) bool {
	for _, r := range key {
		if r < 0x20 || r == 0x7f {
			return true
		}
	}
	return false
}
// before calling: if hasRawControl(key) { /* escape or reject */ }

Type guard

func isSafeConfigKey(key string) bool {
	for _, r := range key {
		if r < 0x20 || r == 0x7f {
			return false
		}
	}
	return key != ""
}

Try / catch

if err := writeConfig(key, val); err != nil {
	if strings.Contains(err.Error(), "unescaped control character") {
		// re-escape key and retry once
	}
	return err
}

Prevention

When it happens

Trigger: Calling the config-write API with a key like "ignore ed" or "my\nkey.x" where a double-quoted segment contains a literal tab, newline, or other control character instead of its backslash escape.

Common situations: 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.

Related errors


AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05). Data as JSON: /api/errors/21d744073286e8de. Report an issue: GitHub.