{"record":{"id":"1537e008d7c05979","repo":"windmill-labs/windmill","slug":"this-pipeline-is-read-only-for-your-role-ai-edits","errorCode":null,"errorMessage":"This pipeline is read-only for your role; AI edits are disabled.","messagePattern":"This pipeline is read-only for your role; AI edits are disabled\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte","lineNumber":497,"sourceCode":"\t// the flow/script editor applies AI edits), which the user then deploys. The\n\t// build/edit logic is shared verbatim with the in-session preview\n\t// (PipelineEditorView) via createPipelineAiHelpers.\n\n\tconst pipelineAiHelpers = createPipelineAiHelpers({\n\t\tgetFolder: () => folder,\n\t\tgetWorkspace: () => $workspaceStore,\n\t\tgetResolvedGraph: () => graphWithDraft,\n\t\tgetDrafts: () => pe.drafts,\n\t\tsetDrafts: (next) => (pe.drafts = next),\n\t\tnewDraftLocalId: pe.newDraftLocalId,\n\t\tonForgetPath: (path) => forgetPath(path),\n\t\tonShowDrafts: () => (includeDrafts = true),\n\t\tonProposeNode: (path) => focusPipelineNode(`script:${path}`),\n\t\tensureEditable: () => {\n\t\t\t// Auto-enter edit so AI changes are visible/actionable, unless the user\n\t\t\t// is an operator (no edit permission) — then refuse with a clear error.\n\t\t\tif (isOperator) {\n\t\t\t\tthrow new Error('This pipeline is read-only for your role; AI edits are disabled.')\n\t\t\t}\n\t\t\tif (mode !== 'edit') setMode('edit')\n\t\t},\n\t\tonRunStarted: (jobId, path) => {\n\t\t\tactiveRunnables.arm(`script:${path}`)\n\t\t\trunsPendingJobId = jobId\n\t\t\trunsRefreshKey++\n\t\t\tactiveRunnable = { kind: 'script', path }\n\t\t\tactiveRunnableJobId = jobId\n\t\t}\n\t})\n\n\tonMount(() => aiChatManager.setPipelineHelpers(pipelineAiHelpers))\n\n\t// Navigation guard state. `pendingNavigationUrl` holds the URL the user\n\t// tried to leave to so we can complete the navigation after they pick\n\t// \"Save all\" or \"Discard all\"; `bypassNavigationGuard` is the standard\n\t// SvelteKit pattern for \"this navigation was already approved, don't","sourceCodeStart":479,"sourceCodeEnd":515,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte#L479-L515","documentation":"The pipeline page's AI assistant calls ensureEditable() before proposing any node edit. If the current user is an operator (lacks edit permission on the pipeline), the page refuses AI edits outright with this error instead of silently entering edit mode where changes would be invisible or unactionable.","triggerScenarios":"An operator-role user asks the AI to modify the pipeline while in view/ops mode; ensureEditable() checks isOperator and throws before setMode('edit').","commonSituations":"Shared workspaces where operators run pipelines but cannot edit; user forgot their role is read-only; attempting AI-generated drafts on a pipeline they can only operate.","solutions":["Ask an editor/admin to make the change, or request edit permission on the pipeline/folder","Operate under an account with write access to the pipeline","Read-only users can still view runs and drafts (onShowDrafts) but not propose edits"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const canEdit = workspaceStore.perms.editable !== false && !isOperator;\nif (!canEdit) throw new Error('Read-only role: AI edits disabled');","typeGuard":"function canProposeEdits(user: {isOperator: boolean}): boolean {\n  return !user.isOperator;\n}","tryCatchPattern":"try { assistant.ensureEditable(); } catch (e) {\n  if (e.message.includes('read-only')) { notify('Request edit access to use AI edits'); }\n  else throw e;\n}","preventionTips":["Hide/disable AI edit actions for operator-role users in the UI","Request edit permission on the pipeline/folder before using AI proposals","Check membership/role on pipeline load and adjust available actions"],"tags":["permissions","pipeline","ai","rbac"],"backgroundTag":"insufficient-permissions","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}