{"record":{"id":"ca05edf7253b6d4e","repo":"langflow-ai/langflow","slug":"share-could-not-be-updated-it-may-conflict-with-a","errorCode":null,"errorMessage":"Share could not be updated: it may conflict with an existing share.","messagePattern":"Share could not be updated: it may conflict with an existing share\\.","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"error","filePath":"src/backend/base/langflow/api/v1/authz_shares.py","lineNumber":441,"sourceCode":"        share_user_id=owner_id,\n    )\n\n    # Validate permission_level (422 before DB CHECK).\n    try:\n        row.permission_level = SharePermissionLevel(payload.permission_level).value\n    except ValueError as exc:\n        raise HTTPException(\n            status_code=400,\n            detail=f\"Unknown permission_level {payload.permission_level!r}\",\n        ) from exc\n    session.add(row)\n    # Rollback + fixed 409 on constraint failure (same as create_share).\n    try:\n        await session.flush()\n    except Exception as exc:\n        await session.rollback()\n        logger.warning(\"authz_share update rejected: %s\", exc)\n        raise HTTPException(\n            status_code=status.HTTP_409_CONFLICT,\n            detail=\"Share could not be updated: it may conflict with an existing share.\",\n        ) from exc\n    await session.refresh(row)\n    response = (await _serialize_shares(session, [row]))[0]\n    await session.commit()\n\n    await _refresh_policy_for_share(response.scope, response.target_id, op=\"share:update\")\n\n    await audit_decision(\n        user_id=current_user.id,\n        action=\"share:update\",\n        obj=f\"{response.resource_type}:{response.resource_id}\",\n        result=\"allow\",\n        details={\n            \"share_id\": str(response.id),\n            \"permission_level\": response.permission_level,\n        },","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/authz_shares.py#L423-L459","documentation":"Raised by PATCH /api/v1/authz/shares/{share_id} when session.flush() fails after updating the row (e.g. a DB CHECK or unique constraint rejects the new state). The handler rolls back, logs 'authz_share update rejected' server-side, and returns a fixed 409 without schema leakage — the mirror of the create path's 409.","triggerScenarios":"PATCHing a share into a state that duplicates another share row on the same resource/scope/target, or a permission_level that violates a DB CHECK despite passing the enum validation.","commonSituations":"Concurrent share edits where two requests converge on conflicting states; updating a share whose target/scope was concurrently changed by another admin.","solutions":["Re-fetch the share (GET /authz/shares/{id}) and reconcile your intended change against its current state before retrying","Do not blind-retry the same PATCH on 409 — inspect what conflicts","Serialize share edits per resource in the client to avoid concurrent conflicting updates"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"async function refreshThenUpdate(shareId: string, level: string) {\n  const current = await getShare(shareId); // fail fast with 404 if gone\n  return updateShare(shareId, { permission_level: level });\n}","typeGuard":null,"tryCatchPattern":"try {\n  await updateShare(shareId, body);\n} catch (e) {\n  if (e.status === 409) {\n    const fresh = await getShare(shareId);\n    // reconcile fresh state with intent, then retry ONCE with corrected body\n  } else throw e;\n}","preventionTips":["Avoid concurrent PATCHes to the same share from multiple clients","On 409, always re-read the row before retrying — never replay the identical body blindly"],"tags":["authz","api","shares","conflict","patch"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}