gravitational/teleport · error

not enough tokens to parse AttributeTypeValue, remaining tok

Error message

not enough tokens to parse AttributeTypeValue, remaining tokens: %s

What it means

parseATV expects a complete AttributeTypeAndValue triple (ATTR '=' STRING). Peek3 requires at least 3 remaining tokens; if fewer remain (e.g. a dangling 'CN=' or 'CN' at the end of the DN), the parser cannot form a triple and returns this error. The remaining tokens are included to help locate the truncation.

Source

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

			}
			if err := markAttr(prevAttr); err != nil {
				return err
			}

		default:
			// Force an error.
			return requireTokenKind(tokenComma, tok, tokens)
		}
	}
}

// parseATV parses an AttributeTypeAndValue.
//
// Eg: "CN" EQUAL "Llama CA".
func parseATV(dst *pkix.Name, tokens tokenList) (attr string, _ error) {
	t1, t2, t3, ok := tokens.Peek3()
	if !ok {
		return "", fmt.Errorf(
			"not enough tokens to parse AttributeTypeValue, remaining tokens: %s",
			tokens,
		)
	}
	if err := requireTokenKind(tokenAttrType, t1, tokens); err != nil {
		return "", err
	}
	if err := requireTokenKind(tokenEqual, t2, tokens); err != nil {
		return "", err
	}
	if err := requireTokenKind(tokenString, t3, tokens); err != nil {
		return "", err
	}

	// Pop tokens before returning. We retain the tokens up until the end so
	// eventual errors include them in the message.
	defer func() {
		tokens.PopSilently()

View on GitHub (pinned to 1283425b60)

Solutions

  1. Ensure every component is a full 'ATTR=VALUE' pair including the final one
  2. Remove dangling/trailing components like a bare 'CN' or 'CN=' with empty value
  3. Trim trailing commas/semicolons from the DN string before parsing
  4. Check that template/variable substitution actually filled the last value

Example fix

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

Strategy: validation

Validate before calling

func completePairs(dn string) error {
	parts := strings.Split(dn, ",")
	for i, part := range parts {
		kv := strings.SplitN(part, "=", 2)
		if len(kv) != 2 || strings.TrimSpace(kv[0]) == "" || kv[1] == "" {
			return fmt.Errorf("component %d (%q) is not a complete ATTR=VALUE pair", i, part)
		}
	}
	return nil
}

Try / catch

if err := completePairs(dn); err != nil { return err }
name, err := pkixname.ParseDistinguishedName(dn)
if err != nil { return fmt.Errorf("invalid DN %q: %w", dn, err) }

Prevention

When it happens

Trigger: DNs ending in a truncated component: 'C=US,O=Teleport,CN' (1 token left) or 'C=US,O=Teleport,CN=' (2 tokens left, empty value still needs the STRING token slot) — Peek3 fails because fewer than 3 tokens remain.

Common situations: Config strings assembled by string concatenation where the last component's value is missing (template variable empty, trailing comma 'C=US,CN=' then split artifacts), or copy-paste truncation in YAML/CLI values.

Related errors


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