{"record":{"id":"ace0cd64a3732e54","repo":"gastownhall/beads","slug":"failed-to-close-encoder-w","errorCode":null,"errorMessage":"failed to close encoder: %w","messagePattern":"failed to close encoder: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/repos.go","lineNumber":147,"sourceCode":"\t\t\tmapping.Content[reposIndex+1] = reposNode\n\t\t}\n\t} else if reposNode != nil {\n\t\t// Add new repos section at the end\n\t\tmapping.Content = append(mapping.Content,\n\t\t\t&yaml.Node{Kind: yaml.ScalarNode, Value: \"repos\"},\n\t\t\treposNode,\n\t\t)\n\t}\n\n\t// Marshal back to YAML\n\tvar buf strings.Builder\n\tencoder := yaml.NewEncoder(&buf)\n\tencoder.SetIndent(2)\n\tif err := encoder.Encode(&root); err != nil {\n\t\treturn fmt.Errorf(\"failed to encode config.yaml: %w\", err)\n\t}\n\tif err := encoder.Close(); err != nil {\n\t\treturn fmt.Errorf(\"failed to close encoder: %w\", err)\n\t}\n\n\t// Write back to file\n\tif err := os.WriteFile(configPath, []byte(buf.String()), 0600); err != nil {\n\t\treturn fmt.Errorf(\"failed to write config.yaml: %w\", err)\n\t}\n\n\t// Reload viper config so changes take effect immediately\n\tif v != nil {\n\t\tif err := v.ReadInConfig(); err != nil {\n\t\t\t// Not fatal - config is on disk, will be picked up on next command\n\t\t\t_ = err // Best effort: viper reload failure is non-fatal since config was already written to disk\n\t\t}\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/config/repos.go#L129-L165","documentation":"After encoding, SetReposInYAML must call encoder.Close() to flush the encoder's internal buffer into the strings.Builder. If Close returns an error, the encoded YAML may be incomplete and the error is wrapped as \"failed to close encoder\".","triggerScenarios":"encoder.Close() returns an error after a successful Encode — in practice this happens when the underlying writer (strings.Builder never fails) or the encoder's internal flush/finish step fails, e.g. from a node state issue mid-flush.","commonSituations":"Encountered mainly with custom io.Writer implementations injected in tests that return errors on flush, or with yaml.v3 internal edge cases; rare in production use with strings.Builder.","solutions":["Check the underlying writer for failures if a non-default writer is used","Log the full wrapped error chain (%w) to identify the root cause","Retry the operation — this is not a persistent config corruption","Update gopkg.in/yaml.v3 to the latest version"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := SetReposInYAML(cfgPath, repos); err != nil {\n    if strings.Contains(err.Error(), \"failed to close encoder\") {\n        log.Printf(\"transient encode-flush failure, retrying: %v\", err)\n        return SetReposInYAML(cfgPath, repos)\n    }\n    return err\n}","preventionTips":["Always use reliable in-memory writers (strings.Builder/bytes.Buffer) for encoding","Keep yaml.v3 updated","Check errors from both Encode and Close — never discard Close's error","In tests, use writers that never fail to isolate logic from I/O errors"],"tags":["yaml","encoding","io"],"backgroundTag":"yaml-encode-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}