gastownhall/beads · error

failed to close encoder: %w

Error message

failed to close encoder: %w

What it means

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".

Source

Thrown at internal/config/repos.go:147

			mapping.Content[reposIndex+1] = reposNode
		}
	} else if reposNode != nil {
		// Add new repos section at the end
		mapping.Content = append(mapping.Content,
			&yaml.Node{Kind: yaml.ScalarNode, Value: "repos"},
			reposNode,
		)
	}

	// Marshal back to YAML
	var buf strings.Builder
	encoder := yaml.NewEncoder(&buf)
	encoder.SetIndent(2)
	if err := encoder.Encode(&root); err != nil {
		return fmt.Errorf("failed to encode config.yaml: %w", err)
	}
	if err := encoder.Close(); err != nil {
		return fmt.Errorf("failed to close encoder: %w", err)
	}

	// Write back to file
	if err := os.WriteFile(configPath, []byte(buf.String()), 0600); err != nil {
		return fmt.Errorf("failed to write config.yaml: %w", err)
	}

	// Reload viper config so changes take effect immediately
	if v != nil {
		if err := v.ReadInConfig(); err != nil {
			// Not fatal - config is on disk, will be picked up on next command
			_ = err // Best effort: viper reload failure is non-fatal since config was already written to disk
		}
	}

	return nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the underlying writer for failures if a non-default writer is used
  2. Log the full wrapped error chain (%w) to identify the root cause
  3. Retry the operation — this is not a persistent config corruption
  4. Update gopkg.in/yaml.v3 to the latest version
Defensive patterns

Strategy: try-catch

Try / catch

if err := SetReposInYAML(cfgPath, repos); err != nil {
    if strings.Contains(err.Error(), "failed to close encoder") {
        log.Printf("transient encode-flush failure, retrying: %v", err)
        return SetReposInYAML(cfgPath, repos)
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/ace0cd64a3732e54. Report an issue: GitHub.