m1k1o/neko · error

unable to unmarshal plugin settings from profile

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.

Solutions

  1. Fix the filetransfer section in the user's profile settings to match the current Settings struct (Enabled bool)
  2. Re-export/recreate the profile from a known-good template for this server version
  3. As a stopgap, remove the plugin block from the profile so the not-found default (Enabled=true) applies
  4. 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

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


AI-assisted analysis of m1k1o/neko@b0f01cedea (2026-09-01). Data as JSON: /api/errors/997f47856fe277ff. Report an issue: GitHub.

Appendix: 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)