sipeed/picoclaw · error
failed to parse security config %s: %w
Error message
failed to parse security config %s: %w
What it means
Returned by loadSecurityConfig when the second yaml.Unmarshal — decoding security.yml directly into the Config struct — fails. The file is valid YAML as a node tree (that was checked first), but its contents do not fit the Config schema: wrong field types, custom UnmarshalYAML methods rejecting values, or duplicate/malformed keys. The message includes the security.yml path plus the wrapped decoder error with field context.
Source
Thrown at pkg/config/security.go:78
// 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
// This will resolve encrypted values for model_list, tools, etc.
if err := yaml.Unmarshal(data, cfg); err != nil {
return fmt.Errorf("failed to parse security config %s: %w", securityPath, err)
}
if err := applyLegacySkillsSecurityConfig(cfg, data); err != nil {
return fmt.Errorf("failed to parse legacy skills security config: %w", err)
}
// Restore channels from saved, then manually merge from security.yml
cfg.Channels = make(ChannelsConfig)
for name, savedBC := range savedChannels {
cfg.Channels[name] = savedBC
}
// If we found a channels node in security.yml, merge it into existing channels
if channelsNode != nil {
if err := cfg.Channels.UnmarshalYAML(channelsNode); err != nil {
return fmt.Errorf("failed to merge channels from security config: %w", err)
}
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Read the wrapped error: it names the failing field/type (e.g. `cannot unmarshal !!str into int`); fix that exact value in security.yml
- Compare your security.yml keys against the current Config struct/version's documented schema — usually a version-upgrade mismatch
- Re-generate security.yml with the current version (save/rotate flow) and re-apply only the values you need
- If migrating from an older release, run the provided migration path instead of manually copying the old file
Example fix
# before provider: timeout: "30s-not-a-number-field" # after provider: timeout: 30
Defensive patterns
Strategy: validation
Validate before calling
// Strict-type decode into the same Config before the real load.
func strictCheck(data []byte, cfg *Config) error {
dec := yaml.NewDecoder(bytes.NewReader(data))
dec.KnownFields(true) // catch unknown keys too
var probe Config
return dec.Decode(&probe)
} Try / catch
if err := loadSecurityConfig(cfg, p); err != nil {
var typeErr *yaml.TypeError
if errors.As(err, &typeErr) {
for _, e := range typeErr.Errors { log.Printf("field error: %s", e) }
}
return err
} Prevention
- Regenerate security.yml with the current version after upgrades instead of reusing old files
- Diff schema docs between versions when bumping
- Avoid moving keys between levels when hand-editing
When it happens
Trigger: A field that must be a scalar holds a map (e.g. `passphrase: {a: 1}`), a numeric field holds a non-number, or a nested type's custom UnmarshalYAML (e.g. ChannelsConfig, model_list entries) rejects a value. yaml.TypeError from the struct decode is wrapped into this message.
Common situations: Schema drift between an old security.yml and a new binary (fields changed shape across versions), hand-editing that moves a key one level up/down, or encrypted/legacy values placed under the wrong section. The specific field is named in the wrapped error text.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- model_name must be a string, got %T
- model_name is required: %#v
- failed to parse legacy skills security config: %w
- failed to parse security config: %w
- failed to merge channels from security config: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/9a9358e70396b84c.
Report an issue: GitHub.