{"record":{"id":"a1045009a4682073","repo":"gravitational/teleport","slug":"not-enough-tokens-to-parse-attributetypevalue-rem","errorCode":null,"errorMessage":"not enough tokens to parse AttributeTypeValue, remaining tokens: %s","messagePattern":"not enough tokens to parse AttributeTypeValue, remaining tokens: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/utils/pkixname/parser.go","lineNumber":145,"sourceCode":"\t\t\t}\n\t\t\tif err := markAttr(prevAttr); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\tdefault:\n\t\t\t// Force an error.\n\t\t\treturn requireTokenKind(tokenComma, tok, tokens)\n\t\t}\n\t}\n}\n\n// parseATV parses an AttributeTypeAndValue.\n//\n// Eg: \"CN\" EQUAL \"Llama CA\".\nfunc parseATV(dst *pkix.Name, tokens tokenList) (attr string, _ error) {\n\tt1, t2, t3, ok := tokens.Peek3()\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\n\t\t\t\"not enough tokens to parse AttributeTypeValue, remaining tokens: %s\",\n\t\t\ttokens,\n\t\t)\n\t}\n\tif err := requireTokenKind(tokenAttrType, t1, tokens); err != nil {\n\t\treturn \"\", err\n\t}\n\tif err := requireTokenKind(tokenEqual, t2, tokens); err != nil {\n\t\treturn \"\", err\n\t}\n\tif err := requireTokenKind(tokenString, t3, tokens); err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// Pop tokens before returning. We retain the tokens up until the end so\n\t// eventual errors include them in the message.\n\tdefer func() {\n\t\ttokens.PopSilently()","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/api/utils/pkixname/parser.go#L127-L163","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure every component is a full 'ATTR=VALUE' pair including the final one","Remove dangling/trailing components like a bare 'CN' or 'CN=' with empty value","Trim trailing commas/semicolons from the DN string before parsing","Check that template/variable substitution actually filled the last value"],"exampleFix":"// before\nParseDistinguishedName(\"C=US,O=Teleport,CN=\")\n// after\nParseDistinguishedName(\"C=US,O=Teleport,CN=proxy\")","handlingStrategy":"validation","validationCode":"func completePairs(dn string) error {\n\tparts := strings.Split(dn, \",\")\n\tfor i, part := range parts {\n\t\tkv := strings.SplitN(part, \"=\", 2)\n\t\tif len(kv) != 2 || strings.TrimSpace(kv[0]) == \"\" || kv[1] == \"\" {\n\t\t\treturn fmt.Errorf(\"component %d (%q) is not a complete ATTR=VALUE pair\", i, part)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err := completePairs(dn); err != nil { return err }\nname, err := pkixname.ParseDistinguishedName(dn)\nif err != nil { return fmt.Errorf(\"invalid DN %q: %w\", dn, err) }","preventionTips":["Trim trailing commas and stray separators before parsing","Verify template variables that supply the last component's value are non-empty","Every component needs all three parts: attribute, '=', value"],"tags":["x509","distinguished-name","parsing","truncated-input"],"backgroundTag":"incomplete-attr-value-pair","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}