April 15, 2026 • Versión: 2026.4.11

SecretRef de API Key de Firecrawl Retorna 401 Unauthorized A Pesar del Estado de Configuración Resuelto

Al usar SecretRefs de 1Password para webFetch.apiKey de Firecrawl, las solicitudes fallan con 401 Unauthorized aunque la configuración del gateway muestra el secreto como resuelto y enmascarado.


🔍 Síntomas

Manifestación principal del error

Cuando las solicitudes web_fetch se enrutan a través del plugin Firecrawl con un SecretRef de 1Password para la clave API, la operación falla con un error de autenticación a pesar de que la puerta de enlace indica que el secreto está correctamente resuelto.

shell

Terminal 1: Verificar el estado de resolución de la configuración

$ openclaw config get plugins.entries.firecrawl.config.webFetch.apiKey –verbose

sourceConfig: “op://openclaw/Firecrawl API key/credential” resolved: “••••••••••••••••” resolvedAt: “2026-04-15T10:23:41Z” status: “resolved”

shell

Terminal 2: Ejecutar solicitud web_fetch

$ openclaw tools web-fetch “https://example.com

Error: Firecrawl API error (401): Unauthorized: Invalid token at FirecrawlProvider.fetch (firecrawl-provider.ts:147) at WebFetchTool.execute (web-fetch-tool.ts:89) at Gateway.handleToolCall (gateway.ts:204)

Discrepancia en la inspección de configuración

La vista de configuración en tiempo de ejecución muestra el campo como resolved y masked, lo que sugiere que la capa de materialización aceptó el SecretRef. Sin embargo, la ruta de solicitud de Firecrawl parece recibir cualquiera de los siguientes:

  • La cadena sin resolver `op://...`
  • Una instantánea de configuración obsoleta o incorrecta
  • Un valor que se resolvió pero no se propagó a la instancia del proveedor

Comandos CLI de diagnóstico

shell

Verificar el registro del plugin y el estado en tiempo de ejecución

openclaw plugins list –verbose | grep -A5 firecrawl

Verificar la clave API real que está utilizando el proveedor

openclaw debug provider firecrawl –show-config

Habilitar el registro de seguimiento para la resolución de secretos

OPENCLAW_LOG_LEVEL=trace openclaw gateway start 2>&1 | grep -i “firecrawl|secretref|apiKey”

Contexto del entorno

  • Versión de OpenClaw: 2026.4.11
  • SO: Ubuntu (kernel de Linux 5.15+)
  • Modo de ejecución: Modo local de puerta de enlace
  • Proveedor de secretos: CLI de 1Password (`op://` esquema)
  • Configuración de puerta de enlace: Archivo de configuración JSON

🧠 Causa raíz

Punto de fallo arquitectónico

El error se origina a partir de un fallo de aislamiento de instantánea de configuración entre la capa de resolución de configuración de la puerta de enlace y la capa de ejecución de solicitudes del proveedor Firecrawl.

┌─────────────────────────────────────────────────────────────────────┐ │ PROCESO DE PUERTA DE ENLACE │ ├─────────────────────────────────────────────────────────────────────┤ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ Cargador de │───▶│ Resolvedor de │───▶│ Instantánea de │ │ │ │ Configuración │ │ Secretos │ │ Configuración │ │ │ │ (JSON/YAML) │ │ (CLI de 1Pwd) │ │ en Runtime │ │ │ └─────────────────┘ └─────────────────┘ └────────┬────────┘ │ │ │ │ │ │ instantánea│ │ │ copiada │ │ ▼ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ WebFetchTool │───▶│ Instancia de │───▶│ Inicialización │ │ │ │ (web-fetch) │ │ FirecrawlProv │ │ del Proveedor │ │ │ └─────────────────┘ └─────────────────┘ └────────┬────────┘ │ │ │ │ │ │ usa │ │ ▼ │ │ ┌─────────────────┐ │ │ │ Llamada REST │ │ │ │ API de Firecrawl│ │ │ └─────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘

Secuencia de fallo

  1. Fase de carga de configuración: La puerta de enlace carga la configuración JSON que contiene `plugins.entries.firecrawl.config.webFetch.apiKey: "op://openclaw/Firecrawl API key/credential"`.
  2. Fase de resolución de secretos: El servicio SecretResolver procesa el SecretRef de 1Password y recupera el token en texto plano. La vista de configuración en tiempo de ejecución muestra correctamente esto como resuelto y enmascarado.
  3. Fase de inicialización del proveedor (ERROR): Cuando se instancia FirecrawlProvider, recibe una instantánea de configuración obsoleta en lugar del objeto de configuración post-resolución. El constructor del proveedor captura:
    // firecrawl-provider.ts - Constructor (con error)
    constructor(config: FirecrawlConfig) {
      // Captura instantánea de configuración al momento de inicialización
      this.apiKey = config.webFetch.apiKey;
      this.baseUrl = config.webFetch.baseUrl;
      // ...
    }
  4. Fase de ejecución de solicitud: Cuando se invoca web_fetch, el proveedor usa this.apiKey, que todavía contiene la cadena SecretRef sin resolver "op://openclaw/Firecrawl API key/credential" porque la instantánea se tomó antes de que la resolución del secreto se completara.
  5. Rechazo de API de Firecrawl: La API de Firecrawl recibe la cadena literal op://... como la clave API, resultando en 401 Unauthorized.

Análisis de ruta de código

La causa raíz se manifiesta en el orden de inicialización dentro de src/plugins/firecrawl/firecrawl-provider.ts:

// Orden de inicialización problemático
class FirecrawlProvider {
  private apiKey: string;
  private baseUrl: string;

  // Llamado durante el inicio de la puerta de enlace, recibe configuración pre-resolución
  constructor(config: FirecrawlConfig) {
    this.apiKey = config.webFetch.apiKey;  // ← Recibe cadena "op://..."
    this.baseUrl = config.webFetch.baseUrl;
  }

  // Este método se llama en tiempo de solicitud, pero usa el valor capturado
  async fetch(url: string): Promise<FetchResult> {
    const headers = {
      'Authorization': `Bearer ${this.apiKey}`,  // ← Envía ref sin resolver
      'Content-Type': 'application/json'
    };
    // ...
  }
}

Contraste con la ruta de texto plano que funciona

Cuando se usa configuración de texto plano, no se requiere resolución de secretos:

{
  "plugins": {
    "entries": {
      "firecrawl": {
        "config": {
          "webFetch": {
            "apiKey": "fc-actual-token-plaintext"  // ← Asignación directa
          }
        }
      }
    }
  }
}

El proveedor recibe y almacena el token real directamente, evitando el mecanismo roto de instantánea.

Patrón arquitectónico relacionado

Este fallo comparte características con el error de materialización en tiempo de ejecución de SecretRef #28359, donde las instantáneas de configuración tomadas en diferentes fases del ciclo de vida contienen estados de resolución inconsistentes. El constructor del proveedor Firecrawl captura el estado al momento de inicialización, pero la resolución del secreto ocurre después de la inicialización para esta ruta de configuración específica.

🛠️ Solución paso a paso

Opción 1: Resolución diferida (Recomendada)

Modificar el proveedor Firecrawl para realizar la resolución de secretos en tiempo de solicitud en lugar de tiempo de construcción.

Archivo: src/plugins/firecrawl/firecrawl-provider.ts

typescript // ANTES (con error) class FirecrawlProvider { private apiKey: string;

constructor(config: FirecrawlConfig) { this.apiKey = config.webFetch.apiKey; // Captura en init }

async fetch(url: string): Promise { const response = await fetch(this.apiEndpoint, { headers: { ‘Authorization’: Bearer ${this.apiKey} } }); } }

// DESPUÉS (corregido) import { SecretResolver } from ‘@openclaw/core/secrets’;

class FirecrawlProvider { private config: FirecrawlConfig; private secretResolver: SecretResolver;

constructor(config: FirecrawlConfig, secretResolver: SecretResolver) { this.config = config; this.secretResolver = secretResolver; // Inyectar resolvedor }

async fetch(url: string): Promise { // Resolver en tiempo de solicitud, no en tiempo de construcción const resolvedApiKey = await this.secretResolver.resolve( this.config.webFetch.apiKey );

const response = await fetch(this.apiEndpoint, {
  headers: { 'Authorization': `Bearer ${resolvedApiKey}` }
});

} }

Archivo: src/plugins/firecrawl/plugin-registration.ts

typescript // ANTES export function registerFirecrawlPlugin(container: PluginContainer) { container.registerSingleton(FirecrawlProvider, (config) => new FirecrawlProvider(config) ); }

// DESPUÉS export function registerFirecrawlPlugin(container: PluginContainer) { container.registerSingleton(FirecrawlProvider, (config, secretResolver) => new FirecrawlProvider(config, secretResolver) ); }

Opción 2: Actualización del proveedor post-resolución

Forzar una actualización del proveedor después de que la resolución de secretos se complete en el ciclo de vida de la puerta de enlace.

Archivo: src/gateway/boot.ts

typescript // Agregar a la secuencia de inicialización de la puerta de enlace async function initializeGateway(config: GatewayConfig) { // Fase 1: Cargar y resolver secretos const resolvedConfig = await configResolver.resolveWithSecrets(config);

// Fase 2: Inicializar proveedores con configuración resuelta await providerRegistry.initialize(resolvedConfig.plugins);

// Fase 3 (CORRECCIÓN): Actualizar todas las instancias de proveedor para asegurar que usen valores resueltos await providerRegistry.refreshAll();

// Fase 4: Iniciar puerta de enlace await gateway.start(); }

Opción 3: Solución alternativa con variable de entorno (Mitigación inmediata)

Si las correcciones a nivel de código no están disponibles, usar la inyección de variable de entorno para la clave API:

Paso 1: Establecer la clave API en tu entorno:

shell export FIRECRAWL_API_KEY=“tu-clave-api-real-de-1password”

Paso 2: Actualizar la configuración para referenciar la variable de entorno:

json { “plugins”: { “entries”: { “firecrawl”: { “enabled”: true, “config”: { “webFetch”: { “apiKey”: “${FIRECRAWL_API_KEY}”, “baseUrl”: “https://api.firecrawl.dev” } } } } } }

Paso 3: Verificar que la variable de entorno sea accesible:

shell echo $FIRECRAWL_API_KEY

Debería mostrar: tu-clave-api-real-de-1password

Si usas CLI de 1Password directamente:

export FIRECRAWL_API_KEY=$(op read “op://openclaw/Firecrawl API key/credential”)

Paso 4: Verificar que la corrección funcione

Después de aplicar cualquier corrección, ejecutar:

shell openclaw tools web-fetch “https://example.com

La salida esperada debe ser el contenido HTML obtenido, no un error 401.

🧪 Verificación

Diagnóstico pre-corrección

Confirmar que el error existe antes de intentar la remediación:

shell

1. Verificar que el SecretRef esté configurado

openclaw config get plugins.entries.firecrawl.config.webFetch.apiKey

Salida esperada:

op://openclaw/Firecrawl API key/credential

2. Verificar que el CLI de 1Password esté autenticado

op vault list

Salida esperada:

Vaults in personal:

├── openclaw

└── …

3. Confirmar que el secreto existe y es accesible

op item get “Firecrawl API key” –vault openclaw

Esperado: Detalles del item con campo de credencial

4. Probar web_fetch (debería fallar antes de la corrección)

openclaw tools web-fetch “https://httpbin.org/headers" –provider firecrawl

Esperado (antes de la corrección):

Error: Firecrawl API error (401): Unauthorized: Invalid token

Esperado (después de la corrección):

{“headers”: {“Host”: “httpbin.org”, …}}

Pasos de verificación post-corrección

Paso 1: Verificar resolución de secretos

shell openclaw config get plugins.entries.firecrawl.config.webFetch.apiKey –verbose

Esperado:

{

“sourceConfig”: “op://openclaw/Firecrawl API key/credential”,

“resolved”: “••••••••••••••••”,

“status”: “resolved”,

“resolvedAt”: “2026-04-15T10:23:41Z”

}

Paso 2: Verificar inicialización del proveedor

shell openclaw debug provider firecrawl –show-config

Esperado: El campo apiKey debe mostrar “••••••••••••••••” (enmascarado)

NO debe mostrar la cadena sin resolver “op://…”

Paso 3: Verificar ejecución de solicitud

shell

Probar con un endpoint simple que devuelve el encabezado Authorization

openclaw tools web-fetch “https://httpbin.org/headers" –provider firecrawl

Esperado: Debe devolver JSON con el encabezado Host visible

No debe ocurrir error 401

Paso 4: Verificar interacción con API de Firecrawl (Modo depuración)

shell OPENCLAW_LOG_LEVEL=debug openclaw tools web-fetch “https://example.com” –provider firecrawl 2>&1 | grep -E “(firecrawl|Firecrawl|Authorization|Authorization: Bearer)”

Esperado: Debe mostrar el token Bearer resuelto que se envía

NO debe mostrar “op://…” en el encabezado Authorization

Paso 5: Suite de pruebas automatizadas

Ejecutar la suite de pruebas del plugin Firecrawl si está disponible:

shell openclaw test –plugin firecrawl –secretref-mode

Esperado: Todas las pruebas pasan incluyendo escenarios de SecretRef

Verificación de código de salida

shell

Caso de éxito

openclaw tools web-fetch “https://example.com” –provider firecrawl echo “Exit code: $?” # Debe ser 0

Caso de fallo (antes de la corrección)

openclaw tools web-fetch “https://example.com” –provider firecrawl echo “Exit code: $?” # Debe ser distinto de cero (típicamente 1)

⚠️ Errores comunes

Trampas específicas del entorno

  • CLI de 1Password sin autenticación:
    Antes de usar SecretRefs, asegurar que el CLI de 1Password esté conectado:
    # Verificar estado de autenticación
    op account list
    

    Si no está autenticado, conectarse:

    op signin

    Verificar acceso al vault:

    op vault list

  • Permisos de acceso al vault:
    La cuenta de 1Password debe tener acceso al vault referenciado en el SecretRef:
    # Verificar permisos del vault
    op account get
    

    Asegurar que el vault “openclaw” sea accesible

    op vault get openclaw

  • Cuenta de servicio vs Cuenta personal:
    Si se ejecuta la puerta de enlace como servicio, asegurar que la cuenta de servicio tenga acceso a 1Password, no solo tu sesión personal:
    # Para servicio systemd, configurar sesión de 1Password mediante entorno o systemd-run
    # Evitar depender de tokens de sesión personales de 1Password

Errores de configuración

  • Doble-resolución en la configuración:
    Si has establecido FIRECRAWL_API_KEY como variable de entorno y también la referencias en la configuración, asegurar que la configuración use la sintaxis ${FIRECRAWL_API_KEY}, no $FIRECRAWL_API_KEY:
    # Incorrecto - se pasará literalmente
    "apiKey": "$FIRECRAWL_API_KEY"
    

    Correcto - se resolverá

    “apiKey”: “${FIRECRAWL_API_KEY}"

  • Espacios en blanco en SecretRefs:
    Los SecretRefs de 1Password no deben tener espacios en blanco al inicio o al final:
    # Incorrecto - puede causar fallo de resolución
    "apiKey": "op://openclaw/Firecrawl API key/credential "
    

    Correcto

    “apiKey”: “op://openclaw/Firecrawl API key/credential”

  • Caracteres especiales en nombres de items:
    Si el nombre del item de 1Password contiene caracteres especiales, codificarlos en URL:
    # Para item nombrado "Firecrawl API (Dev & Prod)"
    "apiKey": "op://openclaw/Firecrawl%20API%20(Dev%20%26%20Prod)/credential"

Errores en tiempo de ejecución

  • Se requiere reiniciar la puerta de enlace:
    Los cambios en SecretRefs requieren un reinicio de la puerta de enlace para que surtan efecto, incluso si la puerta de enlace recarga otros cambios de configuración en caliente:
    # Requerido después de cambiar SecretRef
    openclaw gateway restart
    

    No es suficiente:

    openclaw config reload # Solo recarga configuración no secreta

  • Comportamiento singleton del proveedor:
    Debido al patrón de proveedor singleton, las instancias de proveedor en caché antes de la resolución de secretos continuará usando valores obsoletos hasta que la puerta de enlace se reinicie completamente:
    # Verificar que no haya instancias obsoletas
    openclaw debug provider firecrawl --status
    

    Debe mostrar: “Initialized: true”, “Config Snapshot: fresh”

  • Consideraciones de montaje de volúmenes Docker:
    Si se ejecuta en Docker, asegurar que el socket/credenciales de 1Password estén correctamente montados:
    # Incorrecto - credenciales no disponibles en el contenedor
    docker run openclaw:latest
    

    Correcto - montar socket de 1Password

    docker run -v openclaw_config:/app/config -e OP_SESSION=… openclaw:latest

Problemas específicos de macOS

  • Prompts de acceso a Keychain:
    El CLI de 1Password puede solicitar acceso a Keychain al ejecutarse de forma no interactiva. Usar op signin --account con una cuenta de servicio para entornos de CI/CD.
  • Reenvío de agente SSH:
    Si las credenciales de 1Password se reenvían vía SSH, asegurar que la variable de entorno OP_SESSION también se reenvíe.

Problemas específicos de Windows

  • Separadores de ruta:
    Las rutas de SecretRef usan barras inclinadas hacia adelante incluso en Windows. No convertir a barras inclinadas hacia atrás.
  • Variables de entorno en WSL2:
    Si se ejecuta OpenClaw en WSL2 con 1Password de Windows, configurar el CLI de 1Password en WSL2 y autenticarse allí por separado del host de Windows.

🔗 Errores relacionados

Problema principal relacionado

  • #28359 - Inconsistencia de materialización en tiempo de ejecución de SecretRef
    Problema histórico que describe cómo los valores de SecretRef pueden ser capturados en instantáneas de configuración en diferentes estados de resolución. El error de Firecrawl es una manifestación específica de este patrón más amplio.

Errores relacionados sintomáticamente

  • 401 Unauthorized: Invalid token
    Fallo de autenticación genérico. En este contexto, causado por la cadena literal op://... que se envía como el token Bearer.
  • SecretRef resolution failed: Item not found
    Indica que el item o vault de 1Password especificado en el SecretRef no existe o no es accesible. Diferente del error de Firecrawl—aquí la resolución misma falla.
  • Plugin initialization failed: Config snapshot mismatch
    Error interno de OpenClaw que indica que un plugin recibió configuración inconsistente en diferentes fases de inicialización. Puede aparecer durante el inicio de la puerta de enlace si se altera el orden de inicialización del proveedor Firecrawl.
  • Gateway config validation error: Invalid SecretRef format
    Fallo de validación de esquema si el SecretRef no se ajusta al patrón op://vault/item/field.

Referencia de códigos de error

Código de errorCategoríaDescripción
SECRET_REF_001ResoluciónValidación de formato SecretRef fallida
SECRET_REF_002ResoluciónCLI de 1Password sin autenticación
SECRET_REF_003ResoluciónItem o vault objetivo no accesible
SECRET_REF_004MaterializaciónValor resuelto no propagado al consumidor
PLUGIN_AUTH_401AutenticaciónPlugin recibió credenciales inválidas
PLUGIN_INIT_001InicializaciónProveedor inicializado con instantánea de configuración obsoleta

Consideraciones entre plugins

El mismo patrón de aislamiento de instantánea afecta a otros plugins que:

  • Aceptan claves API o tokens vía SecretRef
  • Inicializan proveedores durante el inicio de la puerta de enlace
  • Usan instancias de proveedor singleton

Plugins potencialmente afectados conocidos:

  • plugins.entries.anthropic.config.apiKey
  • plugins.entries.google.config.credentials
  • plugins.entries.aws.config.accessKeyId
  • plugins.entries.azure.config.subscriptionKey

Verificar que estos plugins no estén experimentando el mismo problema probando sus respectivas configuraciones de SecretRef.

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.