m1k1o/neko · error
unable to unmarshal %s plugin settings from profile: %w
Error message
unable to unmarshal %s plugin settings from profile: %w
What it means
Companion to error 62 but scoped to the session's profile: isEnabledForSession fails when session.Profile().Plugins.Unmarshal("filetransfer", &profile) errors for reasons other than settings-not-found. It means the per-profile filetransfer settings block is present but does not match the plugin's Settings schema.
Source
Thrown at server/internal/plugins/filetransfer/manager.go:63
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, false
}
files, err := ListFiles(m.config.RootDir)
if err != nil {
return err, false
}
m.mu.Lock()
defer m.mu.Unlock()View on GitHub (pinned to b0f01cedea)
Solutions
- Fix the filetransfer section in the user's profile settings to match the current Settings struct (Enabled bool)
- Re-export/recreate the profile from a known-good template for this server version
- As a stopgap, remove the plugin block from the profile so the not-found default (Enabled=true) applies
- Check server/plugin version mismatch: a profile created by a newer/older version may have an incompatible schema
Example fix
// before (profile)
"plugins": { "filetransfer": { "enabled": "on" } }
// after
"plugins": { "filetransfer": { "enabled": true } } Defensive patterns
Strategy: validation
Validate before calling
raw := session.Profile().Plugins.Get("filetransfer")
if raw != nil {
var s Settings
if err := mapToStruct(raw, &s); err != nil {
return fmt.Errorf("profile filetransfer settings invalid: %w", err)
}
} Try / catch
enabled, err := m.isEnabledForSession(session)
if err != nil {
if errors.Is(err, types.ErrPluginSettingsNotFound) {
enabled = true
} else {
log.Error().Err(err).Str("profile", session.Profile().Name()).Msg("malformed profile plugin settings")
return false
}
} Prevention
- Validate profiles when they are created/imported, rejecting unknown field types
- Keep profile schema in sync with the plugin's Settings struct across versions
- Provide a server-side profile validator endpoint admins can run before assigning profiles
When it happens
Trigger: Any file upload/download/delete request whose session profile contains a filetransfer plugin section with malformed fields (wrong types, unknown structure), causing Profile().Plugins.Unmarshal to return a non-ErrPluginSettingsNotFound error.
Common situations: Profile JSON edited by hand or imported from another deployment with an incompatible Settings shape; a profile exported from an older server version where Settings fields changed.
Related errors
- unable to unmarshal %s plugin settings from global settings:
- 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/997f47856fe277ff.
Report an issue: GitHub.