{"record":{"id":"0186776764ff7898","repo":"larksuite/cli","slug":"cli-token-q-is-duplicated","errorCode":null,"errorMessage":"cli token %q is duplicated","messagePattern":"cli token %q is duplicated","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/common/typed_compile_args.go","lineNumber":527,"sourceCode":"\tif result.minItems != nil && result.maxItems != nil && *result.minItems > *result.maxItems {\n\t\treturn result, fmt.Errorf(\"minItems exceeds maxItems\")\n\t}\n\treturn result, nil\n}\n\nfunc parseCLITag(raw string) (typedCLIInput, error) {\n\tvar result typedCLIInput\n\tif raw == \"\" {\n\t\treturn result, nil\n\t}\n\tseen := make(map[string]struct{})\n\tfor _, token := range strings.Split(raw, \";\") {\n\t\tkey, value, ok := strings.Cut(token, \"=\")\n\t\tif !ok || value == \"\" || token != strings.TrimSpace(token) {\n\t\t\treturn result, fmt.Errorf(\"invalid cli token %q\", token)\n\t\t}\n\t\tif _, duplicate := seen[key]; duplicate {\n\t\t\treturn result, fmt.Errorf(\"cli token %q is duplicated\", key)\n\t\t}\n\t\tseen[key] = struct{}{}\n\t\tswitch key {\n\t\tcase \"sources\":\n\t\t\tfor _, source := range strings.Split(value, \"|\") {\n\t\t\t\tresult.ValueSources = append(result.ValueSources, typedValueSource(source))\n\t\t\t}\n\t\tcase \"encoding\":\n\t\t\tresult.Encoding = typedCLIEncoding(value)\n\t\tdefault:\n\t\t\treturn result, fmt.Errorf(\"unknown cli token %q\", key)\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc parseFiniteFloat(value string) (float64, error) {\n\treturn parseFiniteFloatBits(value, 64)","sourceCodeStart":509,"sourceCodeEnd":545,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/common/typed_compile_args.go#L509-L545","documentation":"parseCLITag validates the semicolon-delimited `cli:\"...\"` struct tag grammar for typed input fields. Each token (key=value) may appear at most once; this error fires when the same key is repeated, e.g. two `encoding=` tokens. It is a build-time declaration error caught when the command set is compiled/registered, so a bad tag fails fast instead of silently ignoring the second value.","triggerScenarios":"Declaring a struct field whose `cli` tag repeats a key, e.g. `cli:\"sources=a|b;encoding=json;encoding=text\"`. parseCLITag splits on ';', cuts on '=', and rejects any key already present in the seen-set.","commonSituations":"Copy-pasting a cli tag and forgetting to remove a token; merging two field definitions or rebasing branches where both sides added a token; hand-editing generated or documented tag examples.","solutions":["Remove the duplicated token so each key appears at most once in the cli tag","If you intended multiple sources, use the pipe separator within a single sources token, e.g. sources=a|b","Run the command's compile/startup test (or `go test` on the shortcut package) to confirm the tag parses"],"exampleFix":"// before\nField string `cli:\"encoding=json;encoding=text\"`\n// after\nField string `cli:\"encoding=json\"`","handlingStrategy":"validation","validationCode":"func validateCLITagKeys(raw string) error {\n\tseen := map[string]bool{}\n\tfor _, tok := range strings.Split(raw, \";\") {\n\t\tkey, _, ok := strings.Cut(tok, \"=\")\n\t\tif !ok || key == \"\" { return fmt.Errorf(\"bad token %q\", tok) }\n\t\tif seen[key] { return fmt.Errorf(\"duplicate cli key %q\", key) }\n\t\tseen[key] = true\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep each cli tag to unique keys; never duplicate encoding/sources tokens","Combine multiple sources in one token with the | separator","Add a unit test parsing every declared struct tag in the package"],"tags":["go","struct-tags","cli","validation"],"backgroundTag":"duplicate-struct-tag-key","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}