{"record":{"id":"f123ed63cfb635ae","repo":"moeru-ai/airi","slug":"clipboard-api-is-unavailable","errorCode":null,"errorMessage":"Clipboard API is unavailable","messagePattern":"Clipboard API is unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/stage-ui/src/components/scenes/stage-render-error.vue","lineNumber":45,"sourceCode":"const bugReportSubmitError = shallowRef<unknown>()\n\nfunction openBugReportDialog() {\n  bugReportDescription.value = t('stage.render-error.report-description', {\n    renderer: props.renderer,\n    modelId: props.modelId ?? 'unknown',\n    error: errorMessageFrom(props.error) ?? props.error.message,\n  })\n  bugReportSubmitError.value = undefined\n  showBugReportDialog.value = true\n}\n\nasync function submitBugReport(payload: BugReportDialogSubmitPayload) {\n  bugReportSending.value = true\n  bugReportSubmitError.value = undefined\n\n  try {\n    if (!isClipboardSupported.value)\n      throw new Error('Clipboard API is unavailable')\n\n    await copy(payload.formattedReport)\n    showBugReportDialog.value = false\n  }\n  catch (error) {\n    bugReportSubmitError.value = error\n  }\n  finally {\n    bugReportSending.value = false\n  }\n}\n</script>\n\n<template>\n  <div\n    :class=\"[\n      'absolute inset-0 z-20 p-6',\n      'flex items-center justify-center',","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui/src/components/scenes/stage-render-error.vue#L27-L63","documentation":"stage-render-error.vue builds a bug report and copies it to the clipboard via VueUse's useClipboard({ legacy: true }). isClipboardSupported is false when neither navigator.clipboard (async Clipboard API) nor document.execCommand('copy') (legacy fallback) is available. The code checks the flag before copying and throws this error so the UI can show it inside the bug report dialog.","triggerScenarios":"Submitting the bug report dialog in a non-secure context (page served over http:// on a non-localhost host), an old embedded WebView without the async clipboard API, or an environment where document.execCommand is also unavailable, making both the modern and legacy paths unsupported.","commonSituations":"Running stage-web over plain http on a LAN IP or inside a VM/remote preview; older Electron/Chromium WebView with permissions policies blocking clipboard; iframe sandbox without allow-clipboard-write; headless/automated browsers with clipboard disabled.","solutions":["Serve the app from a secure context: https:// or http://localhost / http://127.0.0.1.","Grant clipboard-read/clipboard-write permission (Permissions-Policy header, or Electron session setPermissionRequestHandler).","Update the embedded WebView/Chromium so navigator.clipboard exists.","As a product fallback, render the report in a selectable textarea so users can copy manually when isClipboardSupported is false."],"exampleFix":"// before\nif (!isClipboardSupported.value)\n  throw new Error('Clipboard API is unavailable')\nawait copy(payload.formattedReport)\n\n// after — degrade gracefully instead of throwing\nif (!isClipboardSupported.value) {\n  manualCopyText.value = payload.formattedReport\n  bugReportSubmitError.value = new Error('Clipboard unavailable — copy the report text below manually.')\n  return\n}\nawait copy(payload.formattedReport)","handlingStrategy":"type-guard","validationCode":"import { useClipboard } from '@vueuse/core'\nconst { copy, isSupported } = useClipboard({ legacy: true })\nif (!isSupported.value) {\n  // render manual-copy fallback (textarea) instead of submitting to copy()\n}","typeGuard":"function isClipboardAvailable(): boolean {\n  return typeof navigator !== 'undefined'\n    && ((navigator.clipboard != null && window.isSecureContext) || typeof document?.execCommand === 'function')\n}","tryCatchPattern":"try {\n  await copy(payload.formattedReport)\n}\ncatch (error) {\n  // Firefox/permission rejections still throw even when isSupported is true\n  bugReportSubmitError.value = error\n}","preventionTips":["Serve over https or localhost so navigator.clipboard exists.","Always provide a manual copy fallback path for the bug report text.","In Electron, allow clipboard in the session permission handler."],"tags":["clipboard","browser-support","secure-context","vueuse"],"backgroundTag":"clipboard-api-unavailable","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:39:53.451Z"}