siyuan-note/siyuan · error · Error
window.siyuan.languages.clipboardPermissionDenied
Error message
window.siyuan.languages.clipboardPermissionDenied
What it means
writeClipboardData on HarmonyOS delegates to the native shell via window.JSHarmony.writeHTMLClipboard / writeClipboard. When the shell returns false — meaning the OS denied clipboard write permission — the function throws an Error carrying the localized message window.siyuan.languages.clipboardPermissionDenied.
Solutions
- Grant the SiYuan app clipboard permission in the HarmonyOS system settings and retry the copy
- Update the Harmony shell (siyuan-harmony) to a version implementing writeHTMLClipboard/writeClipboard correctly
- Catch this error in copy actions and show the localized permission-denied message with a hint to re-copy manually
- Verify window.JSHarmony exists before calling it and degrade to a plain-text fallback copy path
Example fix
// before
writeClipboardData(protyle, textPlain, textHTML, textSiyuan); // throws on Harmony if denied
// after
try {
await writeClipboardData(protyle, textPlain, textHTML, textSiyuan);
} catch (e) {
if (e.message === window.siyuan.languages.clipboardPermissionDenied) {
showMessage(window.siyuan.languages.clipboardPermissionDenied);
}
} Defensive patterns
Strategy: try-catch
Validate before calling
const harmonyClipboardAvailable = typeof window.JSHarmony !== "undefined" && typeof window.JSHarmony.writeClipboard === "function";
Type guard
const hasHarmonyClipboardBridge = (): boolean => typeof (window as any).JSHarmony !== "undefined" && typeof (window as any).JSHarmony.writeHTMLClipboard === "function";
Try / catch
try {
await writeClipboardData(protyle, textPlain, textHTML, textSiyuan);
} catch (e) {
if (e.message === window.siyuan.languages.clipboardPermissionDenied) {
showMessage(window.siyuan.languages.clipboardPermissionDenied);
return;
}
throw e;
} Prevention
- Check for the JSHarmony bridge before calling it and provide a web fallback
- Prompt users to grant clipboard permission on first copy in the Harmony app
- Update the Harmony shell to support writeHTMLClipboard
- Guide users to system settings when the error is caught
When it happens
Trigger: Copying editor content (plain or rich) in the HarmonyOS app while the system clipboard permission is denied or the shell bridge returns false — e.g. user revoked clipboard access, the shell is in a state blocking clipboard writes, or an old Harmony shell lacking writeHTMLClipboard support.
Common situations: User denied the clipboard permission prompt in the Harmony app; OS background-clipboard restrictions; using a Harmony shell version without the JSHarmony clipboard bridge methods (bridge undefined / returns false).
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- failed to write file paths to pasteboard
- Field [assets. .box] should be of type [String]
- Field [assets. ] should be of type [Object]
- Field [assets] must not be empty
- Field [batch] must not be empty
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/f97d670e5a87fb2a.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/protyle/util/compatibility.ts:433
const fallbackToPlainText = options.fallbackToPlainText !== false;
try {
if (isInAndroid()) {
if (textSiyuan) {
window.JSAndroid.writeSiYuanHTMLClipboard(textPlain, textHTML, textSiyuan);
return {status: "rich"};
}
if (textHTML) {
window.JSAndroid.writeHTMLClipboard(textPlain, textHTML);
return {status: "rich"};
}
window.JSAndroid.writeClipboard(textPlain);
return {status: "plain"};
}
if (isInHarmony()) {
if (textHTML || textSiyuan) {
// 使用通用 HTML 注释封装,使旧版鸿蒙壳也不会写入可见的内部格式分隔符。
if (window.JSHarmony.writeHTMLClipboard(textPlain, buildWebClipboardHTML(textHTML, textSiyuan)) === false) {
throw new Error(window.siyuan.languages.clipboardPermissionDenied);
}
return {status: "rich"};
}
if (window.JSHarmony.writeClipboard(textPlain) === false) {
throw new Error(window.siyuan.languages.clipboardPermissionDenied);
}
return {status: "plain"};
}
if (isInIOS()) {
window.webkit.messageHandlers.setClipboard.postMessage(textPlain || textHTML);
return {status: "plain"};
}
if (textHTML && navigator.clipboard?.write && typeof ClipboardItem !== "undefined") {
const clipboardItem: Record<string, Blob> = {};
if (textPlain) {
clipboardItem["text/plain"] = new Blob([textPlain], {type: "text/plain"});
}
const webHTML = buildWebClipboardHTML(textHTML, textSiyuan);View on GitHub (pinned to 9f775e8a12)