usememos/memos · critical · ErrUnsafeAuthenticationConfiguration
password authentication for regular users cannot be disabled
Error message
password authentication for regular users cannot be disabled without an effective identity provider
What it means
ErrUnsafeAuthenticationConfiguration is a sentinel thrown when a stored authentication mutation (e.g. disabling password login) would leave regular users with no way to sign in, because no effective identity provider remains. It is the guard behind UpsertInstanceGeneralSettingSafely and its transactional validation, preventing an instance from being locked out.
Source
Thrown at store/auth_config.go:16
package store
import (
"context"
"time"
"github.com/pkg/errors"
"google.golang.org/protobuf/encoding/protojson"
storepb "github.com/usememos/memos/proto/gen/store"
)
const authenticationMutationMaxAttempts = 3
// ErrUnsafeAuthenticationConfiguration indicates a mutation would lock regular users out.
var ErrUnsafeAuthenticationConfiguration = errors.New("password authentication for regular users cannot be disabled without an effective identity provider")
// AuthenticationConfigState is the stored authentication configuration read inside a transaction.
type AuthenticationConfigState struct {
GeneralSetting *InstanceSetting
IdentityProviders []*IdentityProvider
}
// AuthenticationConfigMutation validates and applies one stored authentication mutation atomically.
type AuthenticationConfigMutation struct {
UpsertGeneralSetting *InstanceSetting
DeleteIdentityProviderID *int32
Validate func(*AuthenticationConfigState) error
}
// UpsertInstanceGeneralSettingSafely validates and stores GENERAL as one serialized operation.
func (s *Store) UpsertInstanceGeneralSettingSafely(ctx context.Context, setting *storepb.InstanceSetting) (*storepb.InstanceSetting, error) {
if setting == nil || setting.Key != storepb.InstanceSettingKey_GENERAL || setting.GetGeneralSetting() == nil {
return nil, errors.New("GENERAL instance setting is required")View on GitHub (pinned to 14d757ce1f)
Solutions
- Create and verify the identity provider first, then disable password authentication
- Compare against errors.Is(err, store.ErrUnsafeAuthenticationConfiguration) to present a clear admin-facing message
- Re-enable password login until at least one IdP is confirmed working
Example fix
// before setting.GeneralSetting.DisallowPasswordLogin = true _, err := s.UpsertInstanceGeneralSettingSafely(ctx, setting) // after // 1) upsert the OAuth2 IdP _, err := s.UpsertIdentityProvider(ctx, idp) // 2) then disable password login setting.GeneralSetting.DisallowPasswordLogin = true _, err = s.UpsertInstanceGeneralSettingSafely(ctx, setting)
Defensive patterns
Strategy: try-catch
Validate before calling
// Before disabling password auth, confirm at least one effective IdP exists:
state := currentState(ctx) // GeneralSetting + IdentityProviders
disabling := newSetting.DisallowPasswordLogin
hasIdP := len(state.IdentityProviders) > 0
if disabling && !hasIdP {
return errors.New("configure an identity provider before disabling passwords")
} Try / catch
_, err := s.UpsertInstanceGeneralSettingSafely(ctx, setting)
if errors.Is(err, store.ErrUnsafeAuthenticationConfiguration) {
// keep password auth enabled; surface a clear message to the admin
return echo.NewHTTPError(http.StatusConflict, err.Error())
} Prevention
- Order auth changes: add and verify an IdP first, then disable passwords
- Always compare with errors.Is against the sentinel, never string matching
When it happens
Trigger: Setting disallow_password_login (or equivalent) in the GENERAL instance setting while the effective IdP list is empty, or deleting the last identity provider while password auth is already disabled.
Common situations: Admins disabling password auth expecting a configured OAuth provider to take over when it was never persisted or is inactive; CI/test instances flipping auth flags; sequential edits where the IdP creation silently failed earlier.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- deployment configuration disables password authentication fo
- Failed to link account. Please sign in to Memos again and re
- SMTP host is required
- SMTP port must be between 1 and 65535
- from email is required
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/c492378324ff0276.
Report an issue: GitHub.