{"record":{"id":"23100a242cc80b19","repo":"gravitational/teleport","slug":"found-s-instead-of-s-remaining-tokens-s","errorCode":null,"errorMessage":"found %s instead of %s, remaining tokens: %s","messagePattern":"found (.+?) instead of (.+?), remaining tokens: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/utils/pkixname/parser.go","lineNumber":228,"sourceCode":"\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"cannot parse OID component %q as int, OID=%q: %w\", val, attr, err)\n\t\t}\n\t\toid = append(oid, num)\n\t}\n\n\tdst.ExtraNames = append(dst.ExtraNames, pkix.AttributeTypeAndValue{\n\t\tType:  oid,\n\t\tValue: value,\n\t})\n\treturn nil\n}\n\nfunc requireTokenKind(wantKind tokenKind, tok *token, tokens tokenList) error {\n\tif tok.kind == wantKind {\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\n\t\t\"found %s instead of %s, remaining tokens: %s\",\n\t\ttok.kind,\n\t\twantKind,\n\t\ttokens,\n\t)\n}\n\ntype tokenKind int\n\nconst (\n\ttokenAttrType = iota + 1\n\ttokenString\n\ttokenEqual\n\ttokenPlus\n\ttokenComma\n)\n\nfunc (k tokenKind) String() string {","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/api/utils/pkixname/parser.go#L210-L246","documentation":"requireTokenKind is the shared token-shape assertion for the DN parser: parseATV uses it to enforce the ATTR EQUAL STRING order, and parseRDNSequence uses it to force an error when an unexpected token appears between components. When the actual token kind differs from the expected kind, this error names both kinds plus the remaining token stream for diagnosis.","triggerScenarios":"Any structural break in an ATV: 'CN value' (missing '='), 'CN==x' (double '='), 'CN=,CN=x' (empty value before comma forcing STRING mismatch), or stray '=' like 'C=US,=x' at component start. Also fires from parseRDNSequence's default branch when a non-comma token follows a completed ATV.","commonSituations":"Typos in DN strings in config files, spaces in unquoted values that were split elsewhere, double equals signs from templating, or semicolon/space-separated lists pasted into a comma-separated field.","solutions":["Read the error's found/expected kinds: it should read ATTR ... EQUAL ... STRING per component; fix the component that breaks this order","Ensure every attribute is followed by exactly one '=' and a non-empty value","Quote values containing spaces with double quotes ('CN=\"My CA\"') or escape inner specials with backslash","Use single '=' only — remove duplicated '=' from templates"],"exampleFix":"// before\nParseDistinguishedName(\"CN==proxy\")\n// after\nParseDistinguishedName(\"CN=proxy\")","handlingStrategy":"validation","validationCode":"func tokenShapeValid(dn string) error {\n\tparts := strings.Split(dn, \",\")\n\tfor _, part := range parts {\n\t\tif strings.Count(part, \"=\") != 1 { return fmt.Errorf(\"component %q must contain exactly one '='\", part) }\n\t\tkv := strings.SplitN(part, \"=\", 2)\n\t\tif strings.TrimSpace(kv[0]) == \"\" || strings.TrimSpace(kv[1]) == \"\" { return fmt.Errorf(\"empty attribute or value in %q\", part) }\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err := tokenShapeValid(dn); err != nil { return err }\nname, err := pkixname.ParseDistinguishedName(dn)\nif err != nil { return fmt.Errorf(\"invalid DN %q: %w\", dn, err) }","preventionTips":["Every component must be exactly ATTR EQUAL STRING — one '=', no empty values","Quote values with spaces: CN=\"My CA\" — unquoted specials like '<', '>', '\"' are rejected","Use '=' only as the separator; escape literal '=' inside values with a backslash","Check the found/expected kinds in the message to pinpoint the broken token"],"tags":["x509","distinguished-name","parsing","tokenizer"],"backgroundTag":"dn-token-sequence-invalid","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}