router-for-me/CLIProxyAPI · error
invalid yaml document structure
Error message
invalid yaml document structure
What it means
Thrown by the config persistence path (config_yaml.go) when the on-disk config.yaml parses as YAML but is not a well-formed single YAML document with content. yaml.Unmarshal succeeded, but the resulting root node is not a DocumentNode or has zero Content nodes (e.g. a completely empty file or a null document). The sanitizer needs a document tree to merge sanitized values back while preserving comments.
Source
Thrown at internal/config/config_yaml.go:27
"gopkg.in/yaml.v3"
)
// SaveConfigPreserveComments writes the config back to YAML while preserving existing comments
// and key ordering by loading the original file into a yaml.Node tree and updating values in-place.
func SaveConfigPreserveComments(configFile string, cfg *Config) error {
persistCfg := cfg
// Load original YAML as a node tree to preserve comments and ordering.
data, err := os.ReadFile(configFile)
if err != nil {
return err
}
var original yaml.Node
if err = yaml.Unmarshal(data, &original); err != nil {
return err
}
if original.Kind != yaml.DocumentNode || len(original.Content) == 0 {
return fmt.Errorf("invalid yaml document structure")
}
if original.Content[0] == nil || original.Content[0].Kind != yaml.MappingNode {
return fmt.Errorf("expected root mapping node")
}
// Marshal the current cfg to YAML, then unmarshal to a yaml.Node we can merge from.
rendered, err := yaml.Marshal(persistCfg)
if err != nil {
return err
}
var generated yaml.Node
if err = yaml.Unmarshal(rendered, &generated); err != nil {
return err
}
if generated.Kind != yaml.DocumentNode || len(generated.Content) == 0 || generated.Content[0] == nil {
return fmt.Errorf("invalid generated yaml structure")
}
if generated.Content[0].Kind != yaml.MappingNode {View on GitHub (pinned to 78f0c4079e)
Solutions
- Put at least one real mapping entry into config.yaml (e.g. 'port: 8317') or restore it from config.example.yaml.
- If the file is empty by accident, copy config.example.yaml to config.yaml and re-edit.
- Check the file was not truncated by a previous crash or a half-completed atomic write.
- Verify with 'cat config.yaml' that the file contains a top-level mapping, not just comments or '---'.
Example fix
# before: config.yaml is empty or only comments # (file exists, zero mappings) # after port: 8317 auth-dir: ./auths
Defensive patterns
Strategy: validation
Validate before calling
#!/bin/sh # config.yaml must contain at least one top-level mapping entry. if [ ! -s config.yaml ] || ! grep -qE '^[A-Za-z0-9_-]+:' config.yaml; then echo "config.yaml is empty or lacks a top-level mapping" >&2 exit 1 fi
Try / catch
if err := persistConfig(cfg, "config.yaml"); err != nil {
if strings.Contains(err.Error(), "invalid yaml document structure") {
log.Errorf("config.yaml is empty or has no document content; restore it from config.example.yaml")
}
return err
} Prevention
- Never mount an empty file over config.yaml; seed it from config.example.yaml.
- Keep config.yaml under version control so truncation is recoverable.
- Persist configs atomically (write temp file + rename) to avoid empty stubs after crashes.
When it happens
Trigger: config.yaml exists but is empty (0 bytes), contains only comments/whitespace, contains only '---' or 'null', or has multiple documents where unmarshal takes a degenerate root. Triggered when the management API or config save flow persists a sanitized config.
Common situations: Fresh deployment where config.yaml was created empty by a container volume mount or a truncated write; a crashed previous save leaving a stub file; a config template that is all comments; kubernetes ConfigMount of an empty file over config.yaml.
Related errors
- expected root mapping node
- decode codex.live-media-relay.allow-private-remote-ips: %w
- decode codex.live-media-relay.disable-private-remote-ips: %w
- failed to read config file: %w
- failed to parse config file: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/ceb788cc5bd7df5d.
Report an issue: GitHub.