{"record":{"id":"99b38016db8cb631","repo":"github/github-mcp-server","slug":"failed-to-unmarshal-toolsets-w","errorCode":null,"errorMessage":"failed to unmarshal toolsets: %w","messagePattern":"failed to unmarshal toolsets: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/github-mcp-server/list_scopes.go","lineNumber":91,"sourceCode":"\t_ = viper.BindPFlag(\"list-scopes-output\", listScopesCmd.Flags().Lookup(\"output\"))\n\n\trootCmd.AddCommand(listScopesCmd)\n}\n\n// formatScopeDisplay formats a scope string for display, handling empty scopes.\nfunc formatScopeDisplay(scope string) string {\n\tif scope == \"\" {\n\t\treturn \"(no scope required for public read access)\"\n\t}\n\treturn scope\n}\n\nfunc runListScopes() error {\n\t// Get toolsets configuration (same logic as stdio command)\n\tvar enabledToolsets []string\n\tif viper.IsSet(\"toolsets\") {\n\t\tif err := viper.UnmarshalKey(\"toolsets\", &enabledToolsets); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to unmarshal toolsets: %w\", err)\n\t\t}\n\t}\n\t// else: enabledToolsets stays nil, meaning \"use defaults\"\n\n\t// Get specific tools (similar to toolsets)\n\tvar enabledTools []string\n\tif viper.IsSet(\"tools\") {\n\t\tif err := viper.UnmarshalKey(\"tools\", &enabledTools); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to unmarshal tools: %w\", err)\n\t\t}\n\t}\n\n\treadOnly := viper.GetBool(\"read-only\")\n\toutputFormat := viper.GetString(\"list-scopes-output\")\n\n\t// Create translation helper\n\tt, _ := translations.TranslationHelper()\n","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/cmd/github-mcp-server/list_scopes.go#L73-L109","documentation":"Returned by runListScopes when viper.UnmarshalKey(\"toolsets\", &enabledToolsets) fails — i.e. the configured 'toolsets' value (from config file, env var, or flag) cannot be decoded into []string. It executes only when viper.IsSet(\"toolsets\") is true, so any value shaped wrong for a string slice (a map, a nested object, a scalar of unexpected type) triggers it. This runs during the list-scopes command, i.e. at CLI startup before any GitHub API traffic.","triggerScenarios":"Config file sets toolsets to a non-list value (e.g. YAML 'toolsets: {repos: enabled}' or 'toolsets: 123'); an env var or flag delivering a type that viper's decoder (mapstructure) cannot convert to []string; malformed JSON/YAML/TOML structure for that key.","commonSituations":"Hand-edited github-mcp-server config where toolsets is written as a map or scalar instead of a list; mixing config formats (JSON toolsets string vs list); version upgrades that changed the expected shape; env var GITHUB_TOOLSETS with bracket/brace characters parsed as structure.","solutions":["Set toolsets as a plain list of strings in the config file: toolsets: [\"repos\", \"issues\"] (YAML) or [\"repos\",\"issues\"] (JSON/TOML array)","Remove the toolsets key entirely to fall back to defaults (enabledToolsets stays nil)","Validate the config file syntax (yaml/json linter) before running the command","Print the effective value with viper (viper.Get(\"toolsets\")) in a scratch program to see the actual decoded type"],"exampleFix":"# before (config.yml)\ntoolsets:\n  repos: enabled\n  issues: enabled\n\n# after\n toolsets: [\"repos\", \"issues\"]","handlingStrategy":"validation","validationCode":"// Validate the configured shape before it reaches viper's decoder\nraw := viper.Get(\"toolsets\")\nswitch raw.(type) {\ncase []string, []any, nil: // ok\ndefault:\n    log.Fatalf(\"'toolsets' must be a list of strings, got %T\", raw)\n}\n// stricter: ensure every element is a string\nif arr, ok := raw.([]any); ok {\n    for _, e := range arr {\n        if _, ok := e.(string); !ok {\n            log.Fatalf(\"toolsets must be a list of strings; got element %T\", e)\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"var enabledToolsets []string\nif viper.IsSet(\"toolsets\") {\n    if err := viper.UnmarshalKey(\"toolsets\", &enabledToolsets); err != nil {\n        // config shape problem: report and exit with a fix hint\n        log.Fatalf(\"invalid 'toolsets' config (must be a list of strings): %v\", err)\n    }\n}","preventionTips":["Always write toolsets as a YAML/JSON array of strings","Lint config files (yamllint/json schema) before deploying","Remove the key instead of setting it to a placeholder scalar to get defaults"],"tags":["configuration","viper","cli","type-mismatch","startup"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}