{"record":{"id":"4ca409dc41c1f8bf","repo":"charmbracelet/crush","slug":"s-s-has-unknown-flag-kind","errorCode":null,"errorMessage":"%s: --%s has unknown flag kind","messagePattern":"(.+?): --(.+?) has unknown flag kind","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/shellconfig/flags.go","lineNumber":178,"sourceCode":"\t\tvar object map[string]any\n\t\tif err := json.Unmarshal([]byte(v), &object); err != nil || object == nil {\n\t\t\treturn nil, 0, fmt.Errorf(\"%s: --%s expects a JSON object, got %q\", args[0], name, v)\n\t\t}\n\t\treturn object, i + 2, nil\n\n\tcase flagJSONAny:\n\t\tv, err := nextArg(args, i, name)\n\t\tif err != nil {\n\t\t\treturn nil, 0, err\n\t\t}\n\t\tvar parsed any\n\t\tif err := json.Unmarshal([]byte(v), &parsed); err != nil {\n\t\t\treturn nil, 0, fmt.Errorf(\"%s: --%s expects valid JSON, got %q: %s\", args[0], name, v, err)\n\t\t}\n\t\treturn parsed, i + 2, nil\n\n\tdefault:\n\t\treturn nil, 0, fmt.Errorf(\"%s: --%s has unknown flag kind\", args[0], name)\n\t}\n}\n\n// nextArg returns args[i+1], erroring if the flag is missing its value.\nfunc nextArg(args []string, i int, flag string) (string, error) {\n\tif i+1 >= len(args) {\n\t\treturn \"\", fmt.Errorf(\"%s: --%s requires a value\", args[0], flag)\n\t}\n\treturn args[i+1], nil\n}\n\n// storeFlag writes a parsed value into target according to spec.op.\nfunc storeFlag(target map[string]any, spec flagSpec, val any) {\n\tswitch spec.op {\n\tcase opSet:\n\t\ttarget[spec.jsonKey] = val\n\tcase opAppend:\n\t\tarr, _ := target[spec.jsonKey].([]any)","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/shellconfig/flags.go#L160-L196","documentation":"This error is the default branch of parseFlagValue's kind switch: it fires when a flagSpec has a flagKind value the parser does not recognize. This is an internal programming error, not a user-input error — it means a developer added a new flagKind constant to the flagKind enum but did not add a corresponding case in parseFlagValue. Because flagKind is an int enum with no exhaustiveness check, the compiler cannot catch the missing case.","triggerScenarios":"A developer defines a new flagKind constant (beyond flagJSONAny) in internal/shellconfig/flags.go and registers a flagSpec using it, then any builtin invocation that reaches that flag via applyFlags hits the default branch. Not reachable by end-user CLI input alone.","commonSituations":"Adding a flag kind (e.g. a future flagStringSlice) and forgetting the switch case; refactoring the enum and reordering iota constants so an unhandled value appears; merging a partial PR that adds the constant but not the parser case.","solutions":["Add a case for the new flagKind in parseFlagValue's switch in internal/shellconfig/flags.go.","Check the flagSpec tables in the shell builtins for a spec whose kind was added without parser support.","As a library change, replace the int enum default with a compile-time exhaustiveness check or a unit test that iterates all flagKind values.","File/fix as a bug in crush; pin or downgrade the version if hit from an unmodified release build."],"exampleFix":"// before (new kind with no case)\nconst flagStringSlice flagKind = iota_last\n// after\n\tcase flagStringSlice:\n\t\tv, err := nextArg(args, i, name)\n\t\tif err != nil { return nil, 0, err }\n\t\treturn strings.Split(v, \",\"), i + 2, nil","handlingStrategy":"type-guard","validationCode":"// Compile-time guard in the library: ensure every flagKind is accounted for\nvar _ = map[flagKind]struct{}{\n    flagString: {}, flagBool: {}, flagBoolTrue: {}, flagInt: {},\n    flagFloat: {}, flagKeyValue: {}, flagJSONObject: {}, flagJSONAny: {},\n} // extend this map when adding a new kind","typeGuard":"func isKnownFlagKind(k flagKind) bool {\n    switch k {\n    case flagString, flagBool, flagBoolTrue, flagInt, flagFloat,\n        flagKeyValue, flagJSONObject, flagJSONAny:\n        return true\n    }\n    return false\n}","tryCatchPattern":"if err := applyFlags(specs, args, start, target, cmd, stderr); err != nil {\n    if strings.Contains(err.Error(), \"has unknown flag kind\") {\n        // library bug: report to crush maintainers, do not retry\n        return fmt.Errorf(\"internal error in shellconfig flags: %w\", err)\n    }\n    return err\n}","preventionTips":["When adding a flagKind constant, always add the matching case in parseFlagValue in the same PR.","Add a unit test that iterates all flagKind values and asserts no 'unknown flag kind' error.","Consider replacing the default branch with a panic during development to fail loudly in tests.","Keep the enum and the switch adjacent in flags.go to reduce drift."],"tags":["go","internal-bug","argument-parsing","unhandled-enum"],"backgroundTag":"unhandled-enum-case","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}