langflow-ai/langflow · error · HTTPException

Invalid API key

Error message

Invalid API key

What it means

Raised by _enforce_a2a_auth when the x-api-key is presented but either fails check_key (unknown/disabled key) or belongs to a different user than the flow owner. The same message covers both cases intentionally: revealing 'valid key, wrong user' would disclose that the key works elsewhere. The key must be issued by the flow's owner account.

Source

Thrown at src/backend/base/langflow/api/v1/a2a.py:136

    # Short writable session (check_key flushes usage counters), closed before
    # dispatch so no lock is held across the up-to-300s run.
    async with session_scope() as session:
        auth_type = await folder_auth_type(flow, session)
        if auth_type == "none":
            return  # public agent
        if auth_type not in ("apikey", "oauth"):
            # Protected folder with a scheme A2A can't enforce: fail closed, never public.
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"A2A access is disabled for this agent: unsupported folder auth type {auth_type!r}.",
            )
        api_key = request.headers.get(A2A_APIKEY_HEADER)
        if not api_key:
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="API key required")
        user = await check_key(session, api_key)
        # Same message for invalid and wrong-owner: don't reveal a key is valid for another user.
        if user is None or user.id != flow.user_id:
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid API key")


class _FlowContextBuilder(DefaultServerCallContextBuilder):
    """Carry the per-request flow_id into the shared executor via call-context state."""

    def build(self, request: Request) -> ServerCallContext:
        context = super().build(request)
        # Canonicalize to the same string form the resume guard uses (str(UUID(...))), so the durable
        # store scope (_task_scope / _push_config_scope) and the checkpoint/resume guard agree even for
        # a non-canonical UUID in the path (uppercase or hyphenless, both valid to the UUID route
        # converter). Without this, the same task addressed via two encodings lands in two scopes.
        context.state["flow_id"] = str(UUID(request.path_params["flow_id"]))
        return context


async def _is_public_a2a_flow(flow: Flow) -> bool:
    """Whether an A2A flow admits callers without an API key."""
    async with session_scope_readonly() as session:

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Regenerate an API key under the flow owner's account and use that in x-api-key
  2. Verify the key still exists and is active in the owner's API-keys page (it may have been revoked)
  3. Confirm flow ownership — if the flow belongs to user A, only user A's keys work; transfer the flow or use the owner's key

Example fix

# before
headers={"x-api-key": os.environ["ADMIN_API_KEY"]}
# after
headers={"x-api-key": os.environ["FLOW_OWNER_API_KEY"]}
Defensive patterns

Strategy: validation

Validate before calling

import httpx

def key_is_live(base_url: str, api_key: str, auth: str) -> bool:
    r = httpx.get(f"{base_url}/api/v1/api_keys/", headers={"x-api-key": api_key}, auth=auth)
    return r.status_code == 200  # a valid, active key lists fine

Try / catch

try:
    resp = await client.send_message(flow_id, payload)
except A2AClientError as e:
    if "Invalid API key" in str(e):
        key = rotate_to_owner_key(flow_id)   # fetch/regenerate under the flow owner
        client = rebuild_client_with_x_api_key(key)
        resp = await client.send_message(flow_id, payload)
    else:
        raise

Prevention

When it happens

Trigger: POST /api/v1/a2a/{flow_id}/jsonrpc with an x-api-key that is revoked, mistyped, from another user's account, or a key created after the server cached key state.

Common situations: Using an admin/personal key from a different account than the one that owns the agent flow; copying a key from another environment; a key revoked or rotated after the client was configured.

Understand the failure class

Related errors


AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14). Data as JSON: /api/errors/c83543be03f3d8e4. Report an issue: GitHub.