{"record":{"id":"f5ca4528b1816088","repo":"mislav/hub","slug":"value-of-host-entry-is-must-be-array-but-got-v","errorCode":null,"errorMessage":"value of host entry is must be array but got %#v","messagePattern":"value of host entry is must be array but got %#v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"github/config_decoder.go","lineNumber":43,"sourceCode":"}\n\nfunc (y *yamlConfigDecoder) Decode(r io.Reader, c *Config) error {\n\td, err := ioutil.ReadAll(r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tyc := yaml.MapSlice{}\n\terr = yaml.Unmarshal(d, &yc)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, hostEntry := range yc {\n\t\tv, ok := hostEntry.Value.([]interface{})\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"value of host entry is must be array but got %#v\", hostEntry.Value)\n\t\t}\n\t\tif len(v) < 1 {\n\t\t\tcontinue\n\t\t}\n\t\thostName, ok := hostEntry.Key.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"host name is must be string but got %#v\", hostEntry.Key)\n\t\t}\n\t\thost := &Host{Host: hostName}\n\t\tfor _, prop := range v[0].(yaml.MapSlice) {\n\t\t\tpropName, ok := prop.Key.(string)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"property name is must be string but got %#v\", prop.Key)\n\t\t\t}\n\t\t\tswitch propName {\n\t\t\tcase \"user\":\n\t\t\t\thost.User, ok = prop.Value.(string)\n\t\t\tcase \"oauth_token\":","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/mislav/hub/blob/5c547ed804368763064e51f3990851e267e88edd/github/config_decoder.go#L25-L61","documentation":"The custom YAML decoder for ~/.config/hub expects each top-level host entry's value to be a YAML array (list of MapSlice property blocks). If a host key maps to anything else (a scalar, a bare map), Decode returns this error describing the actual value. It protects the decoder from malformed config structures.","triggerScenarios":"Decoding a configs file where a host key's value is not a sequence, e.g. `github.com: octocat` or `github.com: {user: octocat}` instead of `github.com:\\n- user: octocat`.","commonSituations":"Hand-edited hub config files; configs written by other tools with a flatter structure; YAML anchors/tags producing non-list values.","solutions":["Rewrite the host entry so its value is a list of property maps: `github.com:\\n- user: octocat\\n  oauth_token: xxxx`.","Restore the file from a backup or let hub regenerate it by deleting the malformed entry.","Validate the YAML structure with a linter before saving."],"exampleFix":"// before (invalid)\ngithub.com:\n  user: octocat\n// after\ngithub.com:\n- user: octocat\n  oauth_token: xxxx","handlingStrategy":"validation","validationCode":"// Parse the config yourself first and check the shape:\nvar raw map[string]interface{}\nyaml.Unmarshal(data, &raw)\nfor name, v := range raw {\n    if _, ok := v.([]interface{}); !ok {\n        log.Fatalf(\"host %q must map to a YAML list, got %T\", name, v)\n    }\n}","typeGuard":"func isHostEntryArray(v interface{}) bool {\n    _, ok := v.([]interface{})\n    return ok\n}","tryCatchPattern":"cfg := &github.Config{}\nif err := cfg.Decode(data); err != nil {\n    if strings.Contains(err.Error(), \"must be array\") {\n        return fmt.Errorf(\"malformed hub config, expected list under host name: %w\", err)\n    }\n    return err\n}","preventionTips":["Never hand-edit ~/.config/hub without validating with a YAML linter","Keep the canonical shape: host name maps to a list of property maps","Back up the config before editing; let hub regenerate it when in doubt"],"tags":["yaml","configuration","decoding","validation"],"backgroundTag":"config-schema-validation-failed","analyzedSha":"5c547ed804368763064e51f3990851e267e88edd","analyzedAt":"2026-09-01T03:34:15.525Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}