Skip to content

Copy buttons crash when navigator.clipboard is unavailable #444

Description

@Edison-A-N

Summary

Several copy buttons can crash with a runtime error when the browser does not expose navigator.clipboard:

Runtime TypeError: Cannot read properties of undefined (reading writeText)

The root cause appears to be repeated unsafe Clipboard API access. In multiple use-copy-to-clipboard hooks, the guard checks navigator.clipboard.writeText directly, so it still throws when navigator.clipboard itself is undefined.

Why this happens

navigator.clipboard is only available in secure contexts and may be missing in HTTP, some WebViews, iframes, or restricted browser environments. The code should feature-detect navigator.clipboard?.writeText before calling it, and ideally use a fallback for unsupported contexts.

Locations found

Unsafe duplicated hooks:

  • workspace/frontend/hooks/use-copy-to-clipboard.ts
  • packages/go/web/hooks/use-copy-to-clipboard.ts
  • sdk/studio/src/hooks/use-copy-to-clipboard.ts

Direct navigator.clipboard.writeText(...) calls in the workspace frontend:

  • workspace/frontend/components/chat/chat-message.tsx
  • workspace/frontend/components/layout/sidebar-content.tsx
  • workspace/frontend/components/connect/connect-agent-view.tsx

Direct calls in packages/go/web:

  • packages/go/web/components/chat/chat-message.tsx
  • packages/go/web/components/layout/workspace-switcher-menu.tsx

Direct calls in sdk/studio:

  • sdk/studio/src/components/chat/CodeBlock.tsx
  • sdk/studio/src/pages/admin/TransportConfig.tsx
  • sdk/studio/src/pages/serviceagents/components/ServiceAgentDetail.tsx
  • sdk/studio/src/stores/llmLogStore.ts already has fallback after catch, but still attempts the unsafe call first

Related renderer calls in packages/launcher/src/renderer:

  • packages/launcher/src/renderer/pages/workspaces/index.tsx
  • packages/launcher/src/renderer/pages/logs/index.tsx
  • packages/launcher/src/renderer/components/chat/Markdown.tsx
  • packages/launcher/src/renderer/components/agent-detail/AgentQuickStart.tsx
  • packages/launcher/src/renderer/components/agent-detail/AgentDetail.tsx
  • packages/launcher/src/renderer/components/credentials/CredentialCard.tsx

Some existing code already has the safer pattern and can be used as reference:

  • sdk/studio/src/pages/admin/ConnectionGuide.tsx
  • sdk/studio/src/pages/admin/components/dashboard/NetworkStatusPanel.tsx

Suggested fix

Introduce a shared safe copy helper, for example:

async function copyTextToClipboard(text: string) {
  if (navigator.clipboard?.writeText) {
    await navigator.clipboard.writeText(text);
    return;
  }

  const textarea = document.createElement("textarea");
  textarea.value = text;
  textarea.style.position = "fixed";
  textarea.style.left = "-9999px";
  document.body.appendChild(textarea);
  textarea.select();
  document.execCommand("copy");
  document.body.removeChild(textarea);
}

Then update the three duplicated hooks and direct call sites to use it.

Expected behavior

Clicking copy buttons should not crash the UI when Clipboard API is unavailable. It should either copy via fallback or show a controlled failure toast.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions