{"record":{"id":"c065f3f893da23e9","repo":"nextai-translator/nextai-translator","slug":"clipboard-api-unavailable","errorCode":null,"errorMessage":"Clipboard API unavailable","messagePattern":"Clipboard API unavailable","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/common/components/TranslationHistory.tsx","lineNumber":440,"sourceCode":"                                                }}\n                                                overrides={{\n                                                    BaseButton: {\n                                                        style: { paddingLeft: '6px', paddingRight: '6px' },\n                                                    },\n                                                }}\n                                            >\n                                                <MdReplay size={16} />\n                                            </Button>\n                                        </Tooltip>\n                                        <Tooltip content={t('Copy to clipboard')} placement='bottom'>\n                                            <Button\n                                                size='mini'\n                                                kind='tertiary'\n                                                onClick={async (event) => {\n                                                    event.stopPropagation()\n                                                    try {\n                                                        if (!navigator?.clipboard?.writeText) {\n                                                            throw new Error('Clipboard API unavailable')\n                                                        }\n                                                        await navigator.clipboard.writeText(item.translatedText)\n                                                        toast(t('Copy to clipboard'), {\n                                                            duration: 3000,\n                                                            icon: '👏',\n                                                        })\n                                                    } catch (error) {\n                                                        console.error(error)\n                                                        toast(t('Copy failed'), {\n                                                            duration: 3000,\n                                                            icon: '⚠️',\n                                                        })\n                                                    }\n                                                }}\n                                                overrides={{\n                                                    BaseButton: {\n                                                        style: { paddingLeft: '6px', paddingRight: '6px' },\n                                                    },","sourceCodeStart":422,"sourceCodeEnd":458,"githubUrl":"https://github.com/nextai-translator/nextai-translator/blob/f57537ee4ad8ec654cb726b9907bab7a1f82601d/src/common/components/TranslationHistory.tsx#L422-L458","documentation":"TranslationHistory's copy button throws 'Clipboard API unavailable' when navigator.clipboard or navigator.clipboard.writeText is missing. The async Clipboard API is only exposed in secure contexts and some webviews/embedded environments omit it entirely, so the guard prevents a TypeError on undefined.writeText.","triggerScenarios":"Clicking the copy button in a non-secure context (http:// page), in a webview without clipboard permission, or in an environment (older browser, some Tauri/extension contexts) where navigator.clipboard is undefined.","commonSituations":"Testing over http://localhost alternatives; Tauri webview builds without clipboard permission configured; older browsers or embedded WebViews lacking the async clipboard API; permission-policy blocked clipboard in iframes.","solutions":["Serve the app over HTTPS (or localhost) so the secure-context Clipboard API is exposed","For Tauri, enable the clipboard-manager plugin/permission and use it as fallback","Use a fallback: document.execCommand('copy') with a hidden textarea when navigator.clipboard is absent","Show the error toast (already caught) advising manual copy"],"exampleFix":"// before\nawait navigator.clipboard.writeText(item.translatedText);\n// after\nif (navigator?.clipboard?.writeText) {\n    await navigator.clipboard.writeText(item.translatedText);\n} else {\n    const ta = document.createElement('textarea');\n    ta.value = item.translatedText;\n    document.body.appendChild(ta); ta.select();\n    document.execCommand('copy'); ta.remove();\n}","handlingStrategy":"fallback","validationCode":"const canCopy = typeof navigator !== 'undefined'\n    && !!navigator?.clipboard?.writeText\n    && (window.isSecureContext || location.hostname === 'localhost');","typeGuard":"function clipboardAvailable(nav: Navigator | undefined): nav is Navigator & { clipboard: Clipboard } {\n    return !!nav?.clipboard && typeof nav.clipboard.writeText === 'function';\n}","tryCatchPattern":"try {\n    await navigator.clipboard.writeText(text);\n} catch (e) {\n    legacyCopy(text); // textarea + document.execCommand('copy')\n}","preventionTips":["Always feature-detect navigator.clipboard before use","Serve the app over HTTPS or localhost (secure context requirement)","In Tauri, grant clipboard-manager permissions or use its plugin API","Keep a execCommand('copy') fallback for old webviews"],"tags":["clipboard","browser-api","permissions"],"backgroundTag":"clipboard-api-unavailable","analyzedSha":"f57537ee4ad8ec654cb726b9907bab7a1f82601d","analyzedAt":"2026-08-31T11:24:08.384Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}