gravitational/teleport · error

special character %q not quoted: %s

Error message

special character %q not quoted: %s

What it means

RFC 2253 requires the special characters '<', '>', and '"' to be escaped or inside a quoted string when they appear in an attribute value. This parser is deliberately strict: an unescaped '<', '>', or '"' in the middle of an unquoted string is a hard error.

Source

Thrown at api/utils/pkixname/parser.go:527

		case tokenizeStateAttrTypeEnd:
			switch r {
			case '=':
				emit(tokenEqual)
				state = tokenizeStateStringStart
			default:
				return nil, fmt.Errorf("want '=' attributeValue, found %q: %s", r, errTrace(pos))
			}

		case tokenizeStateString:
			switch r {
			case '+', ',', ';':
				emitBuffer(tokenString)
				transitionToNameComponent(r)
			case '\\':
				escapeStart()
			case '<', '>', '"':
				// We could '<' and '>', but let's be strict.
				return nil, fmt.Errorf("special character %q not quoted: %s", r, errTrace(pos))
			case ' ':
				trailingSpaceBuf.WriteRune(r)
				state = tokenizeStateStringEnd
			case '=', '#': // Go does this.
				// NOT OK per RFC, should be escaped.
				fallthrough
			default:
				buf.WriteRune(r)
			}

		case tokenizeStateStringEscape:
			switch r {
			case ' ': // Go does this.
				// OK per RFC and allows the "\\ " trick.
				fallthrough
			case ',', '=', '+', '<', '>', '#', ';', '\\', '"':
				buf.WriteRune(r)
				escapeEnd()

View on GitHub (pinned to 1283425b60)

Solutions

  1. Escape the character with a backslash: "CN=\\<Bob\\>".
  2. Wrap the value in double quotes: "CN=\"<Bob>\"" (quotes inside still need escaping).
  3. Strip or replace <, >, " from user-supplied DN values before parsing.

Example fix

// before
name, err := pkixname.ParseDistinguishedName("CN=<Bob>")
// after
name, err := pkixname.ParseDistinguishedName("CN=\\<Bob\\>")
Defensive patterns

Strategy: validation

Validate before calling

func unquotedSpecials(dn string) bool {
	inQuotes := false
	for i := 0; i < len(dn); i++ {
		switch dn[i] {
		case '\\':
			i++
		case '"':
			inQuotes = !inQuotes
		case '<', '>':
			if !inQuotes {
				return true
			}
		}
	}
	return false
}

Try / catch

name, err := pkixname.ParseDistinguishedName(dn)
if err != nil {
	if strings.Contains(err.Error(), "special character") {
		return nil, fmt.Errorf("DN %q contains unquoted <, > or \\\"; escape or quote values", dn)
	}
	return nil, err
}

Prevention

When it happens

Trigger: Calling ParseDistinguishedName with values containing raw angle brackets or quotes, e.g. "CN=<Bob>", "OU=a\"b", "O=we<ird". Note '=' and '#' unescaped in strings also fall through to the same default (appended), but < > " always error.

Common situations: DNs containing XML/HTML-like values such as "O=<Company>", copied from tools that auto-quote, or user-supplied names with quotes that were not escaped.

Related errors


AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02). Data as JSON: /api/errors/9be415600df0dc60. Report an issue: GitHub.