gravitational/teleport · error

malformed RDNs: %w

Error message

malformed RDNs: %w

What it means

ParseDistinguishedName parses an RFC 2253-like DN string (e.g. 'C=US,O=Teleport,CN=Teleport CA') into a pkix.Name. When the low-level parseRDNSequence fails on any attribute-type-and-value in the sequence, the error is wrapped as 'malformed RDNs' — meaning the DN string does not conform to the expected ATTR=VALUE[,ATTR=VALUE...] structure or uses unsupported attributes.

Source

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

	const maxDNLength = 4096 // arbitrary-ish upper value
	switch {
	case dn == "": // Early exit.
		return &pkix.Name{}, nil
	case len(dn) > maxDNLength:
		return nil, errors.New("distinguished name too large, refusing to parse")
	}

	tokens, err := tokenize(dn)
	if err != nil {
		return nil, err
	}

	dst := &pkix.Name{}
	if tokens.Len() == 0 {
		return dst, nil
	}
	if err := parseRDNSequence(dst, *tokens); err != nil {
		return nil, fmt.Errorf("malformed RDNs: %w", err)
	}
	return dst, nil
}

// parseRDNSequence parses a RelativeDistinguishedName sequence, ie, a sequence
// of AttributeTypeAndValue separated by commas or pluses.
func parseRDNSequence(dst *pkix.Name, tokens tokenList) error {
	seenAttrs := make(map[string]struct{})
	markAttr := func(attr string) error {
		if _, ok := seenAttrs[attr]; ok {
			return fmt.Errorf("repeated attributeType %q, remaining tokens: %s", attr, tokens)
		}
		seenAttrs[attr] = struct{}{}
		return nil
	}

	prevAttr, err := parseATV(dst, tokens)
	if err != nil {

View on GitHub (pinned to 1283425b60)

Solutions

  1. Read the wrapped cause (%w) for the exact failing token/component and fix that specific part of the DN
  2. Use comma-separated RFC 2253 syntax: 'C=US,O=Teleport,CN=Teleport CA', not OpenSSL's slash format
  3. Use short attribute names (CN, O, OU, C, ST, L, SERIALNUMBER, POSTALCODE, STREET) instead of common numeric OIDs
  4. Escape special characters (',', '+', '=', '#', ';', etc.) with a backslash inside values

Example fix

// before
ParseDistinguishedName("/C=US/O=Teleport")
// after
ParseDistinguishedName("C=US,O=Teleport")
Defensive patterns

Strategy: validation

Validate before calling

func looksLikeDN(dn string) error {
	if dn == "" { return nil }
	if strings.Contains(dn, "/") { return errors.New("slash-separated DN; use comma-separated RFC2253 form") }
	for _, part := range strings.Split(dn, ",") {
		kv := strings.SplitN(part, "=", 2)
		if len(kv) != 2 || kv[0] == "" || kv[1] == "" { return fmt.Errorf("component %q is not ATTR=VALUE", part) }
	}
	return nil
}

Try / catch

name, err := pkixname.ParseDistinguishedName(dn)
if err != nil {
	var detail string
	if errors.Unwrap(err) != nil { detail = errors.Unwrap(err).Error() }
	return fmt.Errorf("invalid DN %q: %v (%v)", dn, err, detail)
}

Prevention

When it happens

Trigger: Calling ParseDistinguishedName with a DN containing repeated attribute types in separate RDNs, mismatched multi-valued RDNs, truncated components, invalid attribute names, or unknown attribute types — any sub-error from parseRDNSequence gets this wrapper.

Common situations: Users paste DNs copied from OpenSSL output (with '/C=US/O=Org' slash separators, which fail tokenization), use RFC 4514 numeric OIDs for common attributes (2.5.4.3=... instead of CN=...), or supply values with unescaped special characters.

Understand the failure class

Related errors


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