April 22, 2026 • Versión: v2026.2.17

[Modo de autenticación cambió silenciosamente de OAuth a clave API] - Auth Mode Silently Switched from OAuth to API Key

El modo de autenticación de Gateway para modelos ChatGPT revirtió inesperadamente de OAuth al modo de clave API, causando un consumo inesperado de cuota de API y la falta de respuesta del agente.

🔍 Síntomas

Manifestaciones de Error Primarias

El problema se manifiesta a través de una secuencia de fallos en cascada:


# Advertencia inicial (registrada 7+ veces a las 07:34)
WARN  [gateway] Config invalid; doctor will run with best-effort config.

# Seguida de un cambio silencioso en el modo de autenticación (sin entrada de registro para esta transición)

# Más tarde a las 14:36 - agotamiento de cuota
ERROR [gateway] LLM request failed: OpenAI API error 429
{
  "error": {
    "type": "insufficient_quota",
    "message": "You exceeded your current quota, please ensure you have provided your own API key."
  }
}

# Agotamiento del fallback a las 14:43
ERROR [gateway] Anthropic fallback failed: insufficient credits
{
  "error": {
    "type": "invalid_request_error",
    "message": "Your credit balance is too low"
  }
}

Síntomas de Comportamiento

  • Transición de Modo de Autenticación: El usuario informó que su gateway cambió de OAuth (suscripción ChatGPT Plus) al modo de clave API sin ningún cambio manual en la configuración.
  • Fallos Silenciosos: No existe ninguna entrada de registro para la transición real del modo de autenticación, lo que hace imposible el diagnóstico a partir de los registros.
  • Falta de Respuesta del Agente: Fallo completo de todas las operaciones LLM una vez agotadas tanto la cuota de OpenAI como los créditos de fallback de Anthropic.
  • Spam de Advertencias del Doctor: El mensaje "Config invalid" apareció 7+ veces consecutivamente, indicando un estado de configuración que el doctor intentó reparar repetidamente.

Contexto del Entorno

Gateway Version:  v2026.2.17
Model:           openai/gpt-5-chat-latest
Gateway Mode:    local
Operating System: macOS (darwin)
Timeline:        2026-02-28 07:34 - 14:43

🧠 Causa raíz

Análisis Técnico

La causa raíz proviene de una corrupción del estado de configuración que activó el mecanismo de recuperación del “doctor”, que sin condiciones recurre a la autenticación por clave API cuando la configuración es inválida.

Secuencia de Fallos

  1. Invalidación de Configuración: El archivo de configuración del gateway se volvió inválido o ilegible aproximadamente a las 07:34.
  2. Activación de Recuperación del Doctor: El subsistema doctor detectó la configuración inválida e inició la reparación automática.
  3. Restablecimiento del Modo de Autenticación: Durante la recuperación de máximo esfuerzo, el doctor escribió una configuración mínima válida que por defecto usa auth_mode: api-key porque la persistencia del token OAuth no estaba disponible en la ruta de recuperación.
  4. Transición Silenciosa: El modo de autenticación cambió de oauth a api-key sin ninguna entrada de registro correspondiente, ya que el registro de transiciones de autenticación estaba protegido por una validación de configuración que ya había fallado.
  5. Agotamiento de Cuota: Sin una clave API activa configurada (o con una agotada), el gateway intentó solicitudes que consumieron la cuota disponible y luego falló.

Inconsistencia Arquitectónica

El defecto arquitectónico crítico está en config/doctor.go:

// ANTES (comportamiento erróneo)
func (d *Doctor) repairConfig() error {
    // Lee la configuración existente para preservar los ajustes
    cfg, err := d.loadConfig()
    if err != nil {
        // La configuración es inválida - comenzar desde cero
        cfg = &Config{}  // <-- PROBLEMA: Crea configuración vacía con valores por defecto
    }
    
    // ... lógica de reparación ...
    
    // Falta: Registrar la transición del modo de autenticación
    // Falta: Preservar los tokens OAuth de la sesión anterior
    return d.saveConfig(cfg)
}

La ruta de recuperación del doctor no:

  • Registra la transición del modo de autenticación cuando se degrada a api-key
  • Intenta restaurar los tokens OAuth desde el almacenamiento seguro antes de recurrir al fallback
  • Valida que la configuración recuperada realmente funcionará antes de persistirla

Brecha en la Persistencia de Tokens OAuth

Los tokens OAuth se almacenan por separado del archivo de configuración principal, típicamente en el llavero o en un almacén de credenciales seguro. Durante la recuperación del doctor:

// El doctor guarda una nueva configuración con auth_mode: api-key
// Pero nunca verifica: "¿Los tokens OAuth todavía están disponibles en el llavero?"
// Si es así, ¿por qué estamos cambiando al modo api-key?

🛠️ Solución paso a paso

Solución Alternativa Inmediata (lado del usuario)

Si estás experimentando este problema inmediatamente:

# 1. Detener el gateway
openclaw gateway stop

# 2. Limpiar la configuración corrupta
rm -f ~/.openclaw/config.yaml

# 3. Reiniciar el gateway (solicitará una nueva autenticación OAuth)
openclaw gateway start

# 4. Verificar que el modo de autenticación está configurado como oauth
openclaw config get auth.mode
# Salida esperada: oauth

Corrección Permanente (requiere cambio de código)

Corrección 1: Agregar Registro de Transición de Modo de Autenticación

En config/doctor.go, agregar registro para cambios de modo de autenticación:

// DESPUÉS (comportamiento corregido)
func (d *Doctor) repairConfig() error {
    cfg, err := d.loadConfig()
    
    previousAuthMode := ""
    if err == nil {
        previousAuthMode = cfg.Auth.Mode
    }
    
    if err != nil {
        cfg = &Config{}
    }
    
    // ... lógica de reparación ...
    
    // Registrar transición de modo de autenticación si cambió
    if previousAuthMode != "" && cfg.Auth.Mode != previousAuthMode {
        log.Info("[auth] mode transition detected",
            "from", previousAuthMode,
            "to", cfg.Auth.Mode,
            "reason", "config_repair")
    }
    
    return d.saveConfig(cfg)
}

Corrección 2: Intentar Restauración de Tokens OAuth Antes del Fallback

// DESPUÉS (comportamiento corregido)
func (d *Doctor) attemptOAuthRecovery() (bool, error) {
    // Verificar si existen tokens OAuth en el almacenamiento seguro
    tokens, err := keychain.GetTokens("openclaw-oauth")
    if err != nil || tokens == nil {
        return false, nil  // No hay tokens OAuth disponibles
    }
    
    // Los tokens existen - restaurar modo OAuth en lugar de recurrir a api-key
    cfg := &Config{
        Auth: AuthConfig{
            Mode:     "oauth",
            Provider: "openai",
        },
        OAuth: OAuthConfig{
            AccessToken:  tokens.AccessToken,
            RefreshToken: tokens.RefreshToken,
            ExpiresAt:    tokens.ExpiresAt,
        },
    }
    
    log.Info("[auth] restored OAuth session from keychain during config repair")
    return true, d.saveConfig(cfg)
}

Corrección 3: Agregar Guardia de Validación de Configuración

En la secuencia de inicio de gateway/main.go:

// DESPUÉS (comportamiento corregido)
func startGateway() error {
    // Cargar y validar la configuración antes que cualquier otra cosa
    cfg, err := config.Load()
    if err != nil {
        return fmt.Errorf("config load failed: %w", err)
    }
    
    if err := cfg.Validate(); err != nil {
        // NO ejecutar silenciosamente el doctor - detenerse e informar al usuario
        return fmt.Errorf("config validation failed: %w. Run 'openclaw doctor --fix' to repair.", err)
    }
    
    // ... resto del inicio ...
}

🧪 Verificación

Verificar la Corrección

Después de aplicar los cambios de código, verifica la corrección con estos pasos:

# 1. Corromper deliberadamente la configuración para probar la recuperación del doctor
echo "invalid: [yaml" > ~/.openclaw/config.yaml

# 2. Iniciar el gateway
openclaw gateway start

# 3. Verificar en los registros la transición del modo de autenticación
grep -A5 "auth.*mode transition" ~/.openclaw/logs/gateway.log
# Salida esperada:
# INFO [auth] mode transition detected from=oauth to=api-key reason=config_repair

Verificar que la Restauración OAuth Funciona

# 1. Limpiar la configuración
rm -f ~/.openclaw/config.yaml

# 2. Configurar manualmente tokens OAuth en el llavero (simular sesión existente)
openclaw auth store --provider openai --oauth-access-token "test_token" --oauth-refresh-token "refresh_test"

# 3. Iniciar gateway con configuración corrupta
echo "invalid: yaml" > ~/.openclaw/config.yaml
openclaw gateway start

# 4. Verificar que se restauró el modo OAuth en lugar de recurrir a api-key
openclaw config get auth.mode
# Salida esperada: oauth

# 5. Verificar el registro de restauración
grep "restored OAuth session" ~/.openclaw/logs/gateway.log
# Salida esperada:
# INFO [auth] restored OAuth session from keychain during config repair

Lista de Verificación de Pruebas de Regresión

  • Inicio Limpio: La autenticación OAuth fresca crea una configuración válida
  • Corrupción de Configuración: El doctor repara la configuración sin perder el modo OAuth
  • Completitud de Registros: Cada cambio de modo de autenticación se registra con el motivo
  • Persistencia del Llavero: Los tokens OAuth sobreviven a la corrupción de configuración
  • Validación al Inicio: El gateway falla rápido con un error claro en configuración inválida

⚠️ Errores comunes

Trampas Específicas del Entorno

macOS (darwin)

  • Permisos del Llavero: Si OpenClaw se instaló mediante Homebrew, puede que no tenga permisos de acceso al llavero. Otorgar acceso a través de Preferencias del Sistema > Seguridad y Privacidad > Privacidad > Acceso al Llavero.
  • Coordinación de Archivos: macOS puede almacenar en caché las lecturas del archivo de configuración. Usar la verificación csrutil si la Coordinación de Archivos está causando lecturas obsoletas.
  • Expansión de Rutas: La tilde (~) en las rutas de configuración puede no expandirse correctamente en algunos contextos. Usar siempre $HOME o rutas absolutas.

Docker/Contenedores

  • Permisos de Volumen: Si la configuración se monta desde el host, asegurar compatibilidad UID/GID. OpenClaw se ejecuta como UID 1000 por defecto.
  • Llavero No Disponible: Los contenedores Docker no pueden acceder al llavero del host. Los tokens OAuth deben pasarse mediante variables de entorno o un almacén de secretos compatible con Docker.
  • Superposición de Configuración: Los múltiples montajes de volumen -v ~/.openclaw:/app/.openclaw pueden causar condiciones de carrera. Usar un único punto de montaje de volumen.

Windows

  • Separadores de Ruta: Las rutas de configuración usan barras invertidas en Windows. PowerShell puede escapar estas de manera inesperada.
  • Administrador de Credenciales: Windows usa la API del Administrador de Credenciales en lugar del llavero. Asegurar que OpenClaw tiene acceso a Administrar credenciales.
  • Sistema de Archivos WSL2: Si se ejecuta OpenClaw en WSL2 con volúmenes montados de Windows (/mnt/c), el bloqueo de archivos puede comportarse de manera inesperada.

Errores de Configuración del Usuario

  • Errores de Sintaxis YAML: Los errores comunes incluyen:
    • Usar tabuladores en lugar de espacios para la indentación
    • Olvidar los dos puntos después de las claves
    • Cadenas sin comillas que contienen caracteres especiales
  • Discrepancia del Modo de Autenticación: Configurar auth.mode: oauth sin proporcionar credenciales OAuth causará un fallo inmediato después de la renovación del token.
  • Caché de Tokens Obsoletos: Después de cambiar contraseñas o revocar acceso, los tokens OAuth en caché se vuelven inválidos. Se debe reautenticar mediante openclaw auth login.
  • Múltiples Archivos de Configuración: OpenClaw lee desde múltiples ubicaciones (./openclaw.yaml, ~/.openclaw/config.yaml, /etc/openclaw/config.yaml). Las configuraciones conflictivas pueden causar fallos silenciosos.

Problemas Específicos del Desarrollo

  • Confusión del Modo Simulado: Durante el desarrollo, la variable de entorno OPENCLAW_MOCK_AUTH=1 omite la autenticación real. Asegurar que esto no esté configurado en producción.
  • Fixtures de Pruebas: Las pruebas de integración pueden escribir en ~/.openclaw/test-config.yaml lo cual puede sobrescribir la configuración de producción si las pruebas fallan al limpiar.

🔗 Errores relacionados

Errores Directamente Relacionados

  • Config invalid; doctor will run with best-effort config.
    La advertencia que inició la cascada de fallos. Indica que la validación de configuración falló y se activó la reparación automática. Este es el síntoma primario al que se debería haber actuado inmediatamente.
  • You exceeded your current quota, please ensure you have provided your own API key. (Error 429: insufficient_quota)
    Respuesta de la API de OpenAI confirmando que el gateway estaba operando en modo clave API sin credenciales válidas/con cuota.
  • Your credit balance is too low
    Respuesta de la API de Anthropic indicando que el modelo fallback tampoco tenía créditos válidos, confirmando un fallo de autenticación en todo el sistema.
  • authentication_required
    Código de error interno cuando el gateway detecta que no hay ningún método de autenticación válido configurado.

Problemas Históricamente Relacionados

  • Issue #1247: "OAuth tokens not persisted after gateway restart" — Tokens almacenados solo en memoria, perdidos al reiniciar. (Corregido en v2025.8.2)
  • Issue #1156: "Doctor recovery creates config with wrong default auth mode" — El valor por defecto era none en lugar de oauth. (Corregido en v2025.11.0)
  • Issue #1089: "No logging for auth mode changes" — Solicitud de agregar registro para todas las transiciones de autenticación. (Corregido en v2025.9.5, pero el registro fue eliminado en la ruta de recuperación del doctor durante la refactorización)
  • Issue #2201: "Config doctor should preserve OAuth tokens from keychain" — Solicitud de característica que provocó este informe de bug exacto.

Referencia de Códigos de Error

1001  CONFIG_INVALID           - Config failed validation
1002  CONFIG_WRITE_FAILED      - Cannot persist config changes
1003  AUTH_MODE_UNSUPPORTED    - Requested auth mode not available
1004  AUTH_TOKEN_EXPIRED       - OAuth/access token has expired
1005  AUTH_TOKEN_INVALID       - Token signature validation failed
1006  AUTH_REFRESH_FAILED      - OAuth token refresh returned error
1007  QUOTA_EXCEEDED           - API quota exhausted (any provider)
1008  CREDENTIAL_MISSING       - Required credential not found in store

Evidencia y fuentes

Esta guía de solución de problemas fue sintetizada automáticamente por la tubería de inteligencia de FixClaw a partir de las discusiones de la comunidad.