{"record":{"id":"f2a681f37fc36f33","repo":"langflow-ai/langflow","slug":"unknown-scope-scope-r","errorCode":null,"errorMessage":"Unknown scope {scope!r}","messagePattern":"Unknown scope (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"src/backend/base/langflow/api/v1/authz_shares.py","lineNumber":308,"sourceCode":"    await ensure_share_permission(\n        current_user,\n        ShareAction.READ,\n        share_user_id=current_user.id,\n    )\n\n    stmt = select(AuthzShare)\n    if resource_type is not None:\n        stmt = stmt.where(AuthzShare.resource_type == resource_type)\n    if resource_id is not None:\n        stmt = stmt.where(AuthzShare.resource_id == resource_id)\n    if target_id is not None:\n        stmt = stmt.where(AuthzShare.target_id == target_id)\n    if scope is not None:\n        # Reject unknown scope values early (422).\n        try:\n            scope_value = ShareScope(scope).value\n        except ValueError as exc:\n            raise HTTPException(status_code=400, detail=f\"Unknown scope {scope!r}\") from exc\n        stmt = stmt.where(AuthzShare.scope == scope_value)\n\n    # Stable ordering with offset/limit pagination.\n    stmt = stmt.order_by(AuthzShare.created_at.desc(), AuthzShare.id).offset(offset).limit(limit)\n\n    rows = list(await session.exec(stmt))\n\n    is_superuser = getattr(current_user, \"is_superuser\", False)\n    if is_superuser:\n        return await _serialize_shares(session, rows)\n\n    # Pre-fetch team memberships (avoid N+1 per row).\n    team_membership_stmt = select(AuthzTeamMember.team_id).where(AuthzTeamMember.user_id == current_user.id)\n    caller_team_ids: set[UUID] = set(await session.exec(team_membership_stmt))\n\n    # Filter rows by visibility rules for non-superusers.\n    visible: list[AuthzShare] = []\n    owner_cache: dict[tuple[str, UUID], UUID | None] = {}","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/authz_shares.py#L290-L326","documentation":"Raised by GET /api/v1/authz/shares when the optional scope query parameter is not a valid ShareScope enum value. The route converts the raw string with ShareScope(scope) and a ValueError becomes a 400 with the offending value echoed back. (The inline comment says 422, but the code returns 400.)","triggerScenarios":"GET /authz/shares?scope=organisation (misspelled), ?scope=global when the enum only defines e.g. user/team, or any string outside the ShareScope members.","commonSituations":"Hardcoded scope strings drifting from the enum after an upgrade; URL-encoding issues producing unexpected query values; copy-pasting scope values from older API docs.","solutions":["Use only the scope values advertised by the API's OpenAPI schema for ShareScope","Drop the scope parameter entirely if you meant 'all scopes'","Fetch and validate the enum members from /openapi.json at client build time"],"exampleFix":"// before\nGET /api/v1/authz/shares?scope=organisation\n\n// after\nGET /api/v1/authz/shares?scope=organization","handlingStrategy":"type-guard","validationCode":"const SHARE_SCOPES = ['user', 'team']; // mirror ShareScope enum from /openapi.json\nif (scope !== undefined && !SHARE_SCOPES.includes(scope)) {\n  throw new Error(`invalid scope ${scope}`);\n}","typeGuard":"const isShareScope = (s: string): boolean => ['user', 'team'].includes(s);","tryCatchPattern":null,"preventionTips":["Source enum literals from the OpenAPI schema rather than hand-typed strings","Omit the scope filter when listing all shares"],"tags":["authz","api","shares","validation","enum","query-params"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}