{"record":{"id":"382fc2e414739acf","repo":"glanceapp/glance","slug":"could-not-umarshal-repository-into-string-or-struc","errorCode":null,"errorMessage":"could not umarshal repository into string or struct: %v","messagePattern":"could not umarshal repository into string or struct: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/widget-releases.go","lineNumber":121,"sourceCode":"\treturn r\n}\n\ntype releaseRequest struct {\n\tIncludePreleases bool   `yaml:\"include-prereleases\"`\n\tRepository       string `yaml:\"repository\"`\n\n\tsource releaseSource\n\ttoken  *string\n}\n\nfunc (r *releaseRequest) UnmarshalYAML(node *yaml.Node) error {\n\ttype releaseRequestAlias releaseRequest\n\talias := (*releaseRequestAlias)(r)\n\tvar repository string\n\n\tif err := node.Decode(&repository); err != nil {\n\t\tif err := node.Decode(alias); err != nil {\n\t\t\treturn fmt.Errorf(\"could not umarshal repository into string or struct: %v\", err)\n\t\t}\n\t}\n\n\tif r.Repository == \"\" {\n\t\tif repository == \"\" {\n\t\t\treturn errors.New(\"repository is required\")\n\t\t} else {\n\t\t\tr.Repository = repository\n\t\t}\n\t}\n\n\tparts := strings.SplitN(repository, \":\", 2)\n\tif len(parts) == 1 {\n\t\tr.source = releaseSourceGithub\n\t} else if len(parts) == 2 {\n\t\tr.Repository = parts[1]\n\n\t\tswitch parts[0] {","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-releases.go#L103-L139","documentation":"Thrown by releaseRequest.UnmarshalYAML (internal/glance/widget-releases.go:121) when a releases-widget entry in glance.yml is neither a plain string nor a valid releaseRequest struct. The custom unmarshaller first tries node.Decode(&repository) (string form like 'go-gitea/gitea'), and on failure tries node.Decode(alias) (map form with repository:/token:/show-source keys); if both fail, this error wraps the struct-decode error.","triggerScenarios":"A YAML node that is a sequence (repository: [gitea, gitea]), a scalar of wrong type (repository: 12), a map with unknown/misspelled keys or wrong value types (repository: { repo: x } instead of repository: x), or mixed syntax combining string and map forms incorrectly.","commonSituations":"Typing 'repo:' instead of 'repository:', quoting mistakes turning a map into a string, copying example config with placeholder values, or indenting the string form so YAML parses it as a nested map.","solutions":["Use the plain string form: '- go-gitea/gitea' or with prefix '- github:go-gitea/gitea'","Or use the struct form with the exact key 'repository': '- repository: go-gitea/gitea' on its own line, optional 'token:' and 'show-source:' siblings","Check the wrapped error (%v) — it names the struct field that failed to decode","Validate the YAML block with yamllint or a YAML linter before restarting Glance"],"exampleFix":"// before (glance.yml)\nwidget:\n  type: releases\n  repositories:\n    - repo: go-gitea/gitea   # wrong key\n    - [gitea, gitea]         # sequence, not a string\n// after\nwidget:\n  type: releases\n  repositories:\n    - go-gitea/gitea\n    - repository: go-gitea/gitea\n      show-source: true","handlingStrategy":"validation","validationCode":"// Validate a releases entry before it reaches UnmarshalYAML\nfunc isValidReleaseEntry(node yaml.Node) bool {\n    return node.Kind == yaml.ScalarNode || node.Kind == yaml.MappingNode\n}","typeGuard":null,"tryCatchPattern":"if err := widget.Initialize(); err != nil {\n    if strings.Contains(err.Error(), \"could not umarshal repository\") {\n        // config error: point user at the failing releases entry, fail fast at startup\n    }\n}","preventionTips":["Use linters on glance.yml","Keep entries in the documented string or struct forms only","Check startup logs; config errors surface immediately at page render"],"tags":["yaml","config","releases","validation"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}