langflow-ai/langflow · error · HTTPException

Cannot change a2a_card_overrides of a flow you do not own.

Error message

Cannot change a2a_card_overrides of a flow you do not own.

What it means

HTTP 403 from _update_flow: a non-owner edit explicitly changes a2a_card_overrides (the AgentCard customization for A2A) to a value differing from the stored one. Like a2a_enabled it is gated on model_fields_set, so only explicit, differing changes by non-owners are rejected; it exists because card overrides control how the flow is advertised to external A2A agents.

Source

Thrown at src/backend/base/langflow/api/v1/flows_helpers.py:440

                detail="Cannot change fs_path of a flow you do not own.",
            )
        if flow.user_id is not None and flow.user_id != owner_user_id:
            raise HTTPException(
                status_code=403,
                detail="Cannot transfer ownership of a flow you do not own.",
            )
        # ``a2a_enabled`` defaults to False (not None) on FlowCreate, so gate on
        # model_fields_set to block only an explicit, differing change.
        if "a2a_enabled" in flow.model_fields_set and flow.a2a_enabled != existing_flow.a2a_enabled:
            raise HTTPException(
                status_code=403,
                detail="Cannot change a2a_enabled of a flow you do not own.",
            )
        if (
            "a2a_card_overrides" in flow.model_fields_set
            and flow.a2a_card_overrides != existing_flow.a2a_card_overrides
        ):
            raise HTTPException(
                status_code=403,
                detail="Cannot change a2a_card_overrides of a flow you do not own.",
            )

    # Validate fs_path if provided (use `is not None` to catch empty strings).
    # Path safety is scoped to the *owner* — fs_path lives under the owner's
    # storage namespace, so we must not authorize it against the actor's.
    if flow.fs_path is not None:
        await _verify_fs_path(flow.fs_path, owner_user_id, storage_service)

    # Validate folder_id if provided — scoped to the owner so a non-owner
    # cannot land the flow in their own default folder via this code path.
    if flow.folder_id is not None:
        folder = (
            await session.exec(select(Folder).where(Folder.id == flow.folder_id, Folder.user_id == owner_user_id))
        ).first()
        if not folder:
            raise HTTPException(status_code=400, detail="Folder not found")

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Omit a2a_card_overrides from non-owner update payloads.
  2. If the client echoes the object back, send it byte-identical (equal values pass) or strip it.
  3. Have the owner apply card override changes.

Example fix

# before
{"a2a_card_overrides": {"name": "Team Agent"}}   # non-owner
# after
{}                                               # owner applies overrides
Defensive patterns

Strategy: validation

Validate before calling

if (!isOwner && 'a2a_card_overrides' in body && JSON.stringify(body.a2a_card_overrides) !== JSON.stringify(currentFlow.a2a_card_overrides)) delete body.a2a_card_overrides;

Prevention

When it happens

Trigger: PATCH/PUT by a non-owner with a2a_card_overrides in the body whose value differs from existing_flow.a2a_card_overrides — e.g. changing the advertised name/description/authentication of another user's A2A flow.

Common situations: Central teams customising A2A cards across org-owned flows without being the row owner; sync clients that always resend the full card overrides object with minor formatting drift (which counts as a differing value).

Related errors


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