{"record":{"id":"b86296533c1d3c38","repo":"langgenius/dify","slug":"data-source-is-disabled","errorCode":null,"errorMessage":"Data source is disabled.","messagePattern":"Data source is disabled\\.","errorType":"exception","errorClass":"ValueError","httpStatus":400,"severity":"warning","filePath":"api/controllers/console/datasets/data_source.py","lineNumber":219,"sourceCode":"            )\n        )\n        if data_source_binding is None:\n            raise NotFound(\"Data source binding not found.\")\n        # enable binding\n        match action:\n            case \"enable\":\n                if data_source_binding.disabled:\n                    data_source_binding.disabled = False\n                    data_source_binding.updated_at = naive_utc_now()\n                else:\n                    raise ValueError(\"Data source is not disabled.\")\n            # disable binding\n            case \"disable\":\n                if not data_source_binding.disabled:\n                    data_source_binding.disabled = True\n                    data_source_binding.updated_at = naive_utc_now()\n                else:\n                    raise ValueError(\"Data source is disabled.\")\n        return {\"result\": \"success\"}, 200\n\n\n@console_ns.route(\"/notion/pre-import/pages\")\nclass DataSourceNotionListApi(Resource):\n    @setup_required\n    @login_required\n    @account_initialization_required\n    @console_ns.doc(params=query_params_from_model(DataSourceNotionListQuery))\n    @console_ns.response(200, \"Success\", console_ns.models[NotionIntegrateInfoListResponse.__name__])\n    @with_current_user\n    @with_current_tenant_id\n    @with_session(write=False)\n    @model_validate(DataSourceNotionListQuery)\n    def get(\n        self,\n        req_data: DataSourceNotionListQuery,\n        session: Session,","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/datasets/data_source.py#L201-L237","documentation":"Python ValueError raised at data_source.py:219 in the 'disable' branch of DataSourceApi.patch when the caller sends action=disable but data_source_binding.disabled is already True (binding is already disabled). Symmetric to error 456: disabling an already-disabled binding is rejected. Like 456, it is a bare ValueError rather than a proper HTTP exception, so callers may see an unexpected status.","triggerScenarios":"PATCH /console/api/data-source/integrates/<binding_id>/disable on a binding whose disabled flag is already True. The else-branch of `if not data_source_binding.disabled` fires.","commonSituations":"UI shows a binding as enabled while the server already has it disabled; double submit; or a concurrent disable by another admin already completed.","solutions":["Refresh the integrations list to read the current disabled state before toggling.","Make the client idempotent and only call 'disable' when the binding is currently enabled.","Change the endpoint to return success when the desired state already holds.","Convert the ValueError to a proper Conflict/BadRequest HTTP exception for a stable client contract."],"exampleFix":"// before (data_source.py:214-219)\ncase \"disable\":\n    if not data_source_binding.disabled:\n        data_source_binding.disabled = True\n        data_source_binding.updated_at = naive_utc_now()\n    else:\n        raise ValueError(\"Data source is disabled.\")\n// after — idempotent disable\ncase \"disable\":\n    if not data_source_binding.disabled:\n        data_source_binding.disabled = True\n        data_source_binding.updated_at = naive_utc_now()\n    # already disabled: no-op","handlingStrategy":"validation","validationCode":"// Only send 'disable' when the binding is currently enabled.\nif (action === 'disable' && binding.disabled === true) {\n  // already disabled — skip the call\n  return;\n}\nawait patchBinding(binding.id, 'disable');","typeGuard":"function shouldDisable(b: {disabled: boolean}): boolean { return b.disabled === false; }","tryCatchPattern":"try {\n  await patchBinding(bindingId, 'disable');\n} catch (e) {\n  if (/is disabled/i.test(String(e.message||e))) { /* already disabled, ignore */ return; }\n  throw e;\n}","preventionTips":["Confirm current disabled state from a fresh fetch before toggling.","Prevent concurrent toggles from double-firing.","Advocate for returning a stable HTTP status instead of a bare ValueError."],"tags":["datasets","data-source","idempotency","state-conflict"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}