{"record":{"id":"ab5a5e5f2ea11f1b","repo":"nexu-io/open-design","slug":"refresh-is-disabled-for-this-artifact-source","errorCode":null,"errorMessage":"Refresh is disabled for this artifact source.","messagePattern":"Refresh is disabled for this artifact source\\.","errorType":"exception","errorClass":"LiveArtifactRefreshUnavailableError","httpStatus":null,"severity":"warning","filePath":"apps/daemon/src/live-artifacts/refresh-service.ts","lineNumber":162,"sourceCode":"      refreshId,\n      now: refreshStartedAt,\n    });\n    await options.onStarted?.({ refreshId, artifact: running.artifact });\n\n    try {\n      const record = await getLiveArtifact(options);\n      const artifact = record.artifact;\n      const currentDataJson = artifact.document?.dataJson ?? {};\n      const documentSource = artifact.document?.sourceJson;\n      const hasDocumentSource = isSupportedSource(documentSource);\n      const timeouts = normalizeLiveArtifactRefreshTimeouts();\n\n      if (!hasDocumentSource) {\n        throw new LiveArtifactRefreshUnavailableError();\n      }\n\n      if (!hasRefreshPermission(documentSource)) {\n        throw new LiveArtifactRefreshUnavailableError('Refresh is disabled for this artifact source.');\n      }\n\n      const candidate = await withLiveArtifactRefreshRun(\n        liveArtifactRefreshRunRegistry,\n        {\n          projectId: options.projectId,\n          artifactId: options.artifactId,\n          refreshId,\n          totalTimeoutMs: timeouts.totalTimeoutMs,\n          now: refreshStartedAt,\n        },\n        async (run) => {\n          let documentOutput: { output: BoundedJsonObject } | undefined;\n          if (hasDocumentSource) {\n            const step = 'document';\n            const sourceMetadata = documentSourceMetadata(documentSource);\n            const documentStartedAt = nowDate();\n            await appendLog({ step, status: 'running', startedAt: documentStartedAt, source: sourceMetadata });","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/live-artifacts/refresh-service.ts#L144-L180","documentation":"refreshLiveArtifact (refresh-service.ts:161-162) throws LiveArtifactRefreshUnavailableError with this message when the source IS supported (passes isSupportedSource) but source.refreshPermission !== 'manual_refresh_granted_for_read_only' (hasRefreshPermission returns false). The source exists but explicit manual-refresh consent was never granted for the read-only source.","triggerScenarios":"A refresh-capable source (local_file/daemon_tool/connector_tool) exists on the artifact, but source.refreshPermission is undefined or set to a value other than 'manual_refresh_granted_for_read_only'.","commonSituations":"A connector or file source was attached without going through the consent-granting UI; the permission field was dropped during a data migration; an external/connector source that requires explicit user consent for read-only refresh.","solutions":["Grant manual refresh permission for the source (set refreshPermission to 'manual_refresh_granted_for_read_only').","Re-add the source through the consent-granting flow so the permission flag is stamped.","If you control artifact creation, set refreshPermission at the same time you attach sourceJson."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const REFRESH_GRANTED = 'manual_refresh_granted_for_read_only';\nfunction isRefreshPermitted(source: { refreshPermission?: string }): boolean {\n  return source.refreshPermission === REFRESH_GRANTED;\n}\nif (!isRefreshPermitted(source)) {\n  // drive the user through the consent-granting flow first\n}","typeGuard":"function hasManualRefreshConsent(source: unknown): boolean {\n  return typeof source === 'object' && source !== null\n    && (source as { refreshPermission?: string }).refreshPermission === 'manual_refresh_granted_for_read_only';\n}","tryCatchPattern":"try {\n  await refreshLiveArtifact(opts);\n} catch (err) {\n  if (err instanceof LiveArtifactRefreshUnavailableError\n      && err.message === 'Refresh is disabled for this artifact source.') {\n    // prompt the user to grant manual refresh permission\n    return;\n  }\n  throw err;\n}","preventionTips":["Set refreshPermission when attaching a source through the consent flow.","Hide or disable the refresh action when hasRefreshPermission(source) is false.","Treat permission as explicit opt-in; never default external/connector sources to granted."],"tags":["live-artifacts","refresh","permissions","consent"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}