m1k1o/neko · error
unable to unmarshal %s plugin settings from global settings:
Error message
unable to unmarshal %s plugin settings from global settings: %w
What it means
Returned by filetransfer Manager.isEnabledForSession when the global settings payload for the filetransfer plugin exists but cannot be unmarshalled into the plugin's Settings struct. ErrPluginSettingsNotFound is tolerated (defaults apply); any other unmarshal error aborts with this wrapped error, so it signals malformed global plugin config, not absence of config.
Source
Thrown at server/internal/plugins/filetransfer/manager.go:54
}
}
type Manager struct {
logger zerolog.Logger
config *Config
sessions types.SessionManager
shutdown chan struct{}
mu sync.RWMutex
fileList []Item
}
func (m *Manager) isEnabledForSession(session types.Session) (bool, error) {
settings := Settings{
Enabled: true, // defaults to true
}
err := m.sessions.Settings().Plugins.Unmarshal(PluginName, &settings)
if err != nil && !errors.Is(err, types.ErrPluginSettingsNotFound) {
return false, fmt.Errorf("unable to unmarshal %s plugin settings from global settings: %w", PluginName, err)
}
profile := Settings{
Enabled: true, // defaults to true
}
err = session.Profile().Plugins.Unmarshal(PluginName, &profile)
if err != nil && !errors.Is(err, types.ErrPluginSettingsNotFound) {
return false, fmt.Errorf("unable to unmarshal %s plugin settings from profile: %w", PluginName, err)
}
return m.config.Enabled && (settings.Enabled || session.Profile().IsAdmin) && profile.Enabled, nil
}
func (m *Manager) refresh() (error, bool) {
// if file transfer is disabled, return immediately without refreshing
if !m.config.Enabled {
return nil, falseView on GitHub (pinned to b0f01cedea)
Solutions
- Open global settings, find the filetransfer plugin section, and fix field names/types to match the plugin's Settings struct (Enabled bool, etc.)
- Validate the settings JSON/YAML against the Settings struct (age/keys/types) before saving
- Upgrade-related: migrate old config keys to the current Settings schema
- Temporarily delete the plugin settings block so ErrPluginSettingsNotFound applies and defaults (Enabled=true) are used
Example fix
// before (global settings)
plugins:
filetransfer:
enabled: "true" # string, not bool
// after
plugins:
filetransfer:
enabled: true Defensive patterns
Strategy: validation
Validate before calling
raw := settings.Plugins.Get("filetransfer")
if raw != nil {
if _, ok := raw.(map[string]any); !ok {
return fmt.Errorf("filetransfer settings must be an object")
}
if e, ok := raw.(map[string]any)["enabled"]; ok {
if _, ok := e.(bool); !ok {
return fmt.Errorf("filetransfer 'enabled' must be a bool")
}
}
} Type guard
func validFTSettings(s Settings) bool {
return reflect.TypeOf(s.Enabled).Kind() == reflect.Bool
} Try / catch
enabled, err := m.isEnabledForSession(session)
if err != nil {
if errors.Is(err, types.ErrPluginSettingsNotFound) {
enabled = true
} else {
log.Error().Err(err).Msg("check filetransfer plugin settings schema")
return false
}
} Prevention
- Validate plugin settings against the Settings struct on config save, not at request time
- Use JSON schema/config linting in CI for global settings
- After upgrades, run a config migration for changed Settings fields
When it happens
Trigger: A file handler (uploadFileHandler, downloadFileHandler, deleteFileHandler) calls isEnabledForSession; sessions.Settings().Plugins.Unmarshal("filetransfer", &settings) fails with an unmarshal/type error because the global settings JSON/YAML for the plugin has wrong field names or types.
Common situations: Admin hand-edits global config and writes enabled: "yes" (string) instead of a bool, or nests settings under the wrong key; a renamed Settings field after an upgrade leaves stale keys of the wrong type in the config store.
Related errors
- unable to unmarshal %s plugin settings from profile: %w
- screencast not enabled
- stream-src not enabled
- no pipeline found for a codec
- plugin '%s' already added
AI-assisted analysis of m1k1o/neko@b0f01cedea (2026-09-01).
Data as JSON: /api/errors/ba0d5fcb968c5af5.
Report an issue: GitHub.