GraphiteEditor/Graphite · error

Clipboard API unsupported

Error message

Clipboard API unsupported

What it means

Thrown when navigator.clipboard.read() returns a falsy value — the async clipboard read API is not actually usable. In most unsupported environments (insecure origins, old browsers) navigator.clipboard is undefined, so read() throws a TypeError instead; the catch block's matchMessage table routes both cases (message containing "clipboard-read" or this exact text) to the same "This browser does not support reading from the clipboard" dialog.

Source

Thrown at frontend/src/utility-functions/clipboard.ts:98

		selection.addRange(range);
	}

	element.dispatchEvent(new Event("input", { bubbles: true }));
}

export async function triggerClipboardRead(editor: EditorWrapper) {
	// In the try block, attempt to read from the Clipboard API, which may not have permission and may not be supported in all browsers
	// In the catch block, explain to the user why the paste failed and how to fix or work around the problem
	try {
		// Attempt to check if the clipboard permission is denied, and throw an error if that is the case
		// In Firefox, the `clipboard-read` permission isn't supported, so attempting to query it throws an error
		// In Safari, the entire Permissions API isn't supported, so the query never occurs and this block is skipped without an error and we assume we might have permission
		const permission = await navigator.permissions?.query({ name: "clipboard-read" });
		if (permission?.state === "denied") throw new Error("Permission denied");

		// Read the clipboard contents if the Clipboard API is available
		const clipboardItems = await navigator.clipboard.read();
		if (!clipboardItems) throw new Error("Clipboard API unsupported");

		// Read any layer data or images from the clipboard
		const success = await Promise.any(
			Array.from(clipboardItems).map(async (item) => {
				// Read plain text and, if it is a layer, pass it to the editor
				if (item.types.includes("text/plain")) {
					const blob = await item.getType("text/plain");
					const reader = new FileReader();
					reader.onload = () => {
						if (typeof reader.result === "string") editor.pasteText(reader.result);
					};
					reader.readAsText(blob);
					return true;
				}

				// Read an image from the clipboard and pass it to the editor to be loaded
				const imageType = item.types.find((type) => type.startsWith("image/"));

View on GitHub (pinned to c507b35645)

Solutions

  1. Serve the app over HTTPS, or use http://localhost / http://127.0.0.1 which are secure contexts
  2. Upgrade to a browser that supports async clipboard read
  3. Use Ctrl+V — the paste event delivers clipboard content even where clipboard.read() is unavailable
  4. Feature-detect before calling and disable the menu paste entry when unsupported

Example fix

// before
const clipboardItems = await navigator.clipboard.read();
if (!clipboardItems) throw new Error("Clipboard API unsupported");

// after: feature-detect before calling
if (!window.isSecureContext || typeof navigator.clipboard?.read !== "function") {
	throw new Error("Clipboard API unsupported");
}
const clipboardItems = await navigator.clipboard.read();
Defensive patterns

Strategy: type-guard

Type guard

function supportsClipboardRead(): boolean {
	return window.isSecureContext && typeof navigator.clipboard?.read === "function";
}

Try / catch

// Route both the explicit throw and the TypeError from a missing API to the same guidance
try {
	const items = await navigator.clipboard.read();
} catch (err) {
	showDialog(String(err).includes("clipboard") ? unsupportedMessage : String(err));
}

Prevention

When it happens

Trigger: Serving the editor over plain http:// on a non-localhost host — the Clipboard API requires a secure context; browsers without async clipboard read support; calling read() in a webview that never exposes navigator.clipboard.

Common situations: Dev servers exposed to the LAN via an IP address (http://192.168.x.x) instead of localhost; previewing a build over http behind a misconfigured proxy; embedding in webviews or older browsers (async clipboard read needs Chrome/Edge 66+, Firefox 127+, Safari 13.1+).

Related errors


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/43642c7b166c8c8c. Report an issue: GitHub.