{"record":{"id":"9a4369be584c9c5a","repo":"larksuite/cli","slug":"s-got-both-q-and-q-keep-q-and-drop-the-other","errorCode":null,"errorMessage":"%s got both %q and %q — keep %q and drop the other","messagePattern":"(.+?) got both %q and %q — keep %q and drop the other","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/sheets/batch_op_dispatch.go","lineNumber":450,"sourceCode":"\t\t\t}\n\t\t\t// Normalize the surviving spelling to the underscore form the tool\n\t\t\t// bodies use, so exactly one key reaches the flag view.\n\t\t\tif target := strings.ReplaceAll(hv, \"-\", \"_\"); target != k {\n\t\t\t\tif _, taken := input[target]; !taken {\n\t\t\t\t\tinput[target] = input[k]\n\t\t\t\t\tdelete(input, k)\n\t\t\t\t\tcanonical[hv] = target\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif kebab := camelToKebab(k); kebab != \"\" && vocab[kebab] {\n\t\t\tif err := claim(kebab, k); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ttarget := strings.ReplaceAll(kebab, \"-\", \"_\")\n\t\t\tif _, taken := input[target]; taken {\n\t\t\t\treturn fmt.Errorf(\"%s got both %q and %q — keep %q and drop the other\", sc, k, target, target) //nolint:forbidigo // intermediate error; the batch dispatcher wraps it into a typed operations validation error\n\t\t\t}\n\t\t\tif _, taken := input[kebab]; taken && kebab != target {\n\t\t\t\treturn fmt.Errorf(\"%s got both %q and %q — keep %q and drop the other\", sc, k, kebab, kebab) //nolint:forbidigo // intermediate error; the batch dispatcher wraps it into a typed operations validation error\n\t\t\t}\n\t\t\tinput[target] = input[k]\n\t\t\tdelete(input, k)\n\t\t\tcanonical[kebab] = target\n\t\t\tcontinue\n\t\t}\n\t\tif target, ok := aliases[strings.ToLower(hv)]; ok && vocab[target] {\n\t\t\tif err := claim(target, k); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tunderscored := strings.ReplaceAll(target, \"-\", \"_\")\n\t\t\t_, hyphenTaken := input[target]\n\t\t\t_, underscoreTaken := input[underscored]\n\t\t\tif !hyphenTaken && !underscoreTaken {\n\t\t\t\tinput[target] = input[k]","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/sheets/batch_op_dispatch.go#L432-L468","documentation":"normalizeSubOpInputKeys converts a kebab-case vocab key to its canonical snake_case target. If the input already contains the snake_case target while the current kebab-case key is also present, both would fight for the same logical field, so the dispatcher errors and asks you to keep the snake_case key.","triggerScenarios":"Sub-op input contains e.g. both `cell-range` and `cell_range` for a vocab-defined kebab key. The camelToKebab normalization produced a kebab spelling whose snake_case form already exists in the input with its own value.","commonSituations":"Mixing old kebab-case-style payloads with the canonical snake_case format in the same batch op; merging two JSON fragments each using a different convention for the same flag.","solutions":["Drop the kebab-case spelling and keep the snake_case key (`target`) with your intended value.","If both are intended for the same field, copy the kebab value into the snake_case key and delete the kebab one.","Normalize your payload generator to emit snake_case keys only."],"exampleFix":"// before\n{\"values\": [...], \"cell-range\": \"A1:B2\", \"cell_range\": \"C3:D4\"}\n// after\n{\"values\": [...], \"cell_range\": \"C3:D4\"}","handlingStrategy":"validation","validationCode":"func hasKebabSnakeConflict(op map[string]interface{}) bool {\n    for k := range op {\n        if strings.Contains(k, \"-\") {\n            if _, exists := op[strings.ReplaceAll(k, \"-\", \"_\")]; exists {\n                return true\n            }\n        }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use snake_case keys exclusively in batch op inputs.","Normalize camelCase/kebabCase keys to snake_case before dispatching.","Validate merged payloads for duplicate logical fields."],"tags":["sheets","validation","naming-convention"],"backgroundTag":"conflicting-parameter-spelling","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"}