gravitational/teleport · error

want attributeType, found EOF

Error message

want attributeType, found EOF

What it means

The DN string ended while the tokenizer was expecting the start of a new attribute type — i.e. the input ended right after a ',' or '+' separator with no following RDN. Trailing separators are invalid; every separator must be followed by another type=value pair.

Source

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

				buf.WriteRune(r)
			}

		case tokenizeStateStringQuoteEnd:
			switch r {
			case '+', ',', ';':
				transitionToNameComponent(r)
			default:
				return nil, fmt.Errorf("want '+' or ',', found %q: %s", r, errTrace(pos))
			}
		}
	}

	// Input ended, check the final state.
	switch state {
	case tokenizeStateInit:
		// OK.
	case tokenizeStateNameComponent:
		return nil, fmt.Errorf("want attributeType, found EOF")
	case tokenizeStateAttrType:
		return nil, fmt.Errorf("want attributeType or '=', found EOF")
	case tokenizeStateAttrTypeEnd:
		return nil, fmt.Errorf("want '=' attributeValue, found EOF")
	case tokenizeStateStringStart, tokenizeStateString, tokenizeStateStringEnd:
		// OK.
		emitBuffer(tokenString)
	case tokenizeStateStringEscape:
		return nil, fmt.Errorf("want escaped character, found EOF")
	case tokenizeStateStringQuote:
		return nil, fmt.Errorf("want closing quote, found EOF")
	case tokenizeStateStringQuoteEnd:
		// OK.
	default:
		// This should not be reached. All states are handled above.
		return nil, fmt.Errorf("found EOF (state=%d)", state)
	}

View on GitHub (pinned to 1283425b60)

Solutions

  1. Remove the trailing ',' or '+' from the DN string.
  2. Filter out empty components before building the DN (skip empty attribute slices when joining).
  3. Pre-validate that the DN does not end with a separator before parsing.

Example fix

// before
name, err := pkixname.ParseDistinguishedName("CN=Bob,O=Corp,")
// after
name, err := pkixname.ParseDistinguishedName("CN=Bob,O=Corp")
Defensive patterns

Strategy: validation

Validate before calling

func trailingSeparator(dn string) bool {
	dn = strings.TrimRight(dn, " ")
	return strings.HasSuffix(dn, ",") || strings.HasSuffix(dn, "+") || strings.HasSuffix(dn, ";")
}

Try / catch

name, err := pkixname.ParseDistinguishedName(dn)
if err != nil {
	if strings.HasSuffix(dn, ",") || strings.HasSuffix(dn, "+") {
		return nil, fmt.Errorf("DN %q ends with a separator", dn)
	}
	return nil, err
}

Prevention

When it happens

Trigger: Calling ParseDistinguishedName with a DN ending in ',' or '+', e.g. "CN=Bob,", "O=Corp,CN=Bob+", or input truncated after a separator.

Common situations: DNs built by joining components with strings.Join over a slice with an empty trailing element, config lines truncated, or copy-paste that dropped the last component.

Related errors


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