sipeed/picoclaw · error
channel %q: failed to decode settings: %w
Error message
channel %q: failed to decode settings: %w
What it means
Inside the RegisterSafeFactory wrapper, bc.GetDecoded() parses/decrypts a channel's settings block into a concrete settings struct; failure is wrapped as "channel %q: failed to decode settings". The underlying cause is preserved with %w and is typically malformed settings content, a wrong shape for the target struct, or a secret that cannot be decrypted with the current key.
Source
Thrown at pkg/channels/registry.go:51
//
// func init() {
// channels.RegisterSafeFactory(config.ChannelTelegram,
// func(bc *config.Channel, c *config.TelegramSettings, b *bus.MessageBus) (channels.Channel, error) {
// return NewTelegramChannel(bc, c, b)
// })
// }
func RegisterSafeFactory[S any](
channelType string,
ctor func(bc *config.Channel, settings *S, bus *bus.MessageBus) (Channel, error),
) {
RegisterFactory(channelType, func(channelName, _ string, cfg *config.Config, b *bus.MessageBus) (Channel, error) {
bc := cfg.Channels[channelName]
if bc == nil {
return nil, fmt.Errorf("channel %q: config not found", channelName)
}
decoded, err := bc.GetDecoded()
if err != nil {
return nil, fmt.Errorf("channel %q: failed to decode settings: %w", channelName, err)
}
settings, ok := decoded.(*S)
if !ok {
return nil, fmt.Errorf("channel %q: expected %T settings, got %T", channelName, (*S)(nil), decoded)
}
return ctor(bc, settings, b)
})
}
// getFactory looks up a channel factory by name.
func getFactory(name string) (ChannelFactory, bool) {
factoriesMu.RLock()
defer factoriesMu.RUnlock()
f, ok := factories[name]
return f, ok
}
// GetRegisteredFactoryNames returns a slice of all registered channel factory names.View on GitHub (pinned to 49183d7e8d)
Solutions
- Unwrap the error (errors.Unwrap / %v) — decode libraries name the exact field and reason; fix that field in the channels.<name> stanza.
- If settings are encrypted/secret-protected, ensure the decryption key/environment (devkey/secret registry) is the one that encrypted them, or re-enter the settings in plaintext and re-encrypt.
- Run a config-validate pass or load the config in a test harness to catch decode errors before channel startup.
- After upgrades, diff your settings block against the current struct definition for that channel type.
Example fix
// before: shipping config errors to users
ch, err := channels.Build(name, cfg, bus)
if err != nil { return err }
// after: log the decode cause with the channel name
if err != nil {
var decodeErr *json.UnmarshalTypeError // or yaml error via errors.As
if errors.As(err, &decodeErr) {
log.Printf("config error in channels.%s field %s: %v", name, decodeErr.Field, err)
}
return err
} Defensive patterns
Strategy: validation
Validate before calling
// dry-run decode during config validation
for name, bc := range cfg.Channels {
if _, err := bc.GetDecoded(); err != nil {
return fmt.Errorf("channel %s settings invalid: %w", name, err)
}
} Try / catch
// if err != nil && strings.Contains(err.Error(), "failed to decode settings") -> unwrap (errors.Unwrap) to get field-level cause; fail startup with the channel name in the message
Prevention
- Run config through a validator/test loader in CI before deploy
- Keep encrypted settings and their decryption key paired — never copy one without the other
- After upgrades, re-decode all channel settings in a smoke test
When it happens
Trigger: Settings YAML/JSON for the channel is syntactically broken or has wrong field types (e.g. webhooks: "string" where a map is expected); settings stored encrypted but the decryption key changed or is missing; env-var placeholders in settings that expand to invalid values; schema drift after an upgrade moved fields.
Common situations: Upgrading the app to a version with a new settings schema while old config files keep removed fields with wrong types; moving an encrypted config file between hosts with different secret keys; hand-editing a locked/encrypted channel block; secrets referenced by name that no longer resolve.
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
- channel %q: expected %T settings, got %T
- channel %q: config not found
- must be in range 1-65535
- ✗ registry '%s' not found or not enabled. check your config
- failed to load MCP servers: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/b771f74759f127fb.
Report an issue: GitHub.