Repository navigation
Comments can't be posted when the UI is served over plain HTTP #15191
brianbrandtdk
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
I'm not sure where to send "bugs" to Paperclip - so I just threw it here. Let me know, where else, if so? :-)
Comments can't be posted when the UI is served over plain HTTP (self-hosted, non-localhost): crypto.randomUUID is not available outside secure contexts
Self-hosted Paperclip, deploymentMode: authenticated, reachable over a VPN at http://:8008 (Caddy → 127.0.0.1:3100). Seen on 2026.916.0 and still on 2026.1001.0.
Symptom: From the Mac that runs the server (via localhost) everything works. From any other machine, over plain HTTP, you can create tasks, browse, assign — but posting a comment silently does nothing. No request ever reaches the server, so there is nothing in the server log.
Cause: The comment submit path calls crypto.randomUUID() with no fallback. Browsers only expose that function in a secure context — HTTPS or localhost — so on http:// it is undefined and the submit handler throws before the request is made.
Unguarded call sites I found:
ui/src/components/IssueChatThread.tsx — attemptId = crypto.randomUUID() in the send handler (~line 4994)
ui/src/pages/IssueDetail.tsx — addComment mutation, clientRequestId ?? crypto.randomUUID() (~line 4455)
also unguarded: components/task-chat/TaskChatComposer.tsx, components/DecisionResolver.tsx, components/chat/ExternallyConnectedTaskBanner.tsx, lib/provider-credential.ts, pages/apps/chat/EmailEndpointSetup.tsx
Other places already do guard it, so the codebase is just inconsistent — e.g. lib/optimistic-issue-comments.ts, lib/cross-tab-poll.ts, components/task-chat/RunnerGoalWidget.tsx, hooks/useDocumentAnnotationMutations.ts.
Minimal repro: Serve the built UI on a non-loopback hostname over HTTP, open the console, type typeof crypto.randomUUID → "undefined". Try to post a comment → crypto.randomUUID is not a function.
Suggested fix: Route every call through one shared helper that falls back to crypto.getRandomValues() (available in insecure contexts), as the guarded files already do. Something like:
ts
export function uuid(): string {
if (typeof crypto?.randomUUID === "function") return crypto.randomUUID();
const b = crypto.getRandomValues(new Uint8Array(16));
b[6] = (b[6] & 0x0f) | 0x40;
b[8] = (b[8] & 0x3f) | 0x80;
const h = [...b].map((x) => x.toString(16).padStart(2, "0")).join("");
return
${h.slice(0,8)}-${h.slice(8,12)}-${h.slice(12,16)}-${h.slice(16,20)}-${h.slice(20)};}
For now we work around it by injecting that polyfill into ui-dist/index.html on the server, which fixes it for all clients. HTTPS would also fix it, but a self-hosted instance on an internal hostname has no publicly trusted certificate, and many IT departments won't install a private root CA on client machines — so plain HTTP on a private network is worth supporting.
All reactions