sipeed/picoclaw · error

failed to parse security config: %w

Error message

failed to parse security config: %w

What it means

Returned by loadSecurityConfig when the first yaml.Unmarshal of security.yml into a yaml.Node fails — i.e. the file is not syntactically valid YAML at all. The node parse is a pure syntax check before any typed decoding happens, so this error means broken YAML structure: tab indentation, unbalanced quotes/brackets, bad anchors/aliases.

Source

Thrown at pkg/config/security.go:57

	data, err := os.ReadFile(securityPath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return fmt.Errorf("failed to read security config: %w", err)
	}

	// Save existing channels and ModelList before unmarshal
	savedChannels := make(ChannelsConfig, len(cfg.Channels))
	for name, bc := range cfg.Channels {
		savedChannels[name] = bc
	}
	// savedModelList := cfg.ModelList

	// Parse YAML into a yaml.Node tree to extract channels node
	var rootNode yaml.Node
	if err := yaml.Unmarshal(data, &rootNode); err != nil {
		return fmt.Errorf("failed to parse security config: %w", err)
	}

	// Extract channels node (support both 'channels' and 'channel_list' keys)
	var channelsNode *yaml.Node
	if len(rootNode.Content) > 0 {
		content := rootNode.Content[0].Content
		for i := 0; i < len(content); i += 2 {
			if i+1 < len(content) {
				key := content[i].Value
				if key == "channels" || key == "channel_list" {
					channelsNode = content[i+1]
					break
				}
			}
		}
	}

	// Unmarshal non-channel fields from security.yml

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Run a YAML lint/parse check on the file: `yamllint security.yml` or `python -c "import yaml,sys;yaml.safe_load(open('security.yml'))"` to get the exact line/column
  2. Replace tabs with spaces for indentation and fix the reported construct (quote, bracket, alias)
  3. Restore from a backup or re-generate security.yml via the app's save/rotate path if hand-repair is impractical
  4. Re-run the config load to confirm the parse succeeds

Example fix

# before (tab indentation)
model_list:
	- model_name: gpt-4o

# after (spaces)
model_list:
  - model_name: gpt-4o
Defensive patterns

Strategy: validation

Validate before calling

// Syntax-check security.yml before app startup.
func yamlSyntaxOK(path string) error {
	data, err := os.ReadFile(path)
	if err != nil { return err }
	var node yaml.Node
	return yaml.Unmarshal(data, &node)
}

Try / catch

if err := loadSecurityConfig(cfg, p); err != nil {
	var yamlErr *yaml.TypeError
	if errors.As(err, &yamlErr) {
		// decode error: fix schema in file
	}
	return err // syntax errors surface as wrapped yaml errors; show file+line
}

Prevention

When it happens

Trigger: security.yml contains a tab character used for indentation, an unclosed quote or bracket, an undefined YAML alias (`*foo` with no `&foo`), or duplicate keys that the parser rejects. Any of these make yaml.Unmarshal(data, &rootNode) return a syntax error which is wrapped here.

Common situations: Hand-editing security.yml in an editor that inserts tabs, pasting YAML from a website/chat that mangles indentation, or truncated files after a crash mid-write. Because the file is written atomically by saveSecurityConfig, corruption almost always comes from manual edits or external tooling.

Understand the failure class

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/4b39689ec4fdf592. Report an issue: GitHub.