{"record":{"id":"0750bfd834036f8c","repo":"coder/code-server","slug":"crypto-subtle-is-not-available-so-webviews-will","errorCode":null,"errorMessage":"'crypto.subtle' is not available so webviews will not work. This is likely because the editor is not running in a secure context (https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts).","messagePattern":"'crypto\\.subtle' is not available so webviews will not work\\. This is likely because the editor is not running in a secure context \\(https://developer\\.mozilla\\.org/en-US/docs/Web/Security/Secure_Contexts\\)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"patches/webview.diff","lineNumber":77,"sourceCode":" \t\t\tconst swPath = encodeURI(`service-worker.js?v=${expectedWorkerVersion}&vscode-resource-base-authority=${searchParams.get('vscode-resource-base-authority')}&remoteAuthority=${searchParams.get('remoteAuthority') ?? ''}&platform=${searchParams.get('platform')}`);\n-\t\t\tnavigator.serviceWorker.register(swPath, { type: 'module', updateViaCache: 'none' })\n+\t\t\tnavigator.serviceWorker.register(swPath)\n \t\t\t\t.then(async registration => {\n \t\t\t\t\tif (navigator.serviceWorker.controller) {\n \t\t\t\t\t\t// A previous SW is already controlling. Force an update\n@@ -332,6 +332,12 @@\n \n \t\t\t\tconst hostname = location.hostname;\n \n+\t\t\t\t// It is safe to run if we are on the same host.\n+\t\t\t\tconst parent = new URL(parentOrigin)\n+\t\t\t\tif (parent.hostname === hostname) {\n+\t\t\t\t\treturn start(parentOrigin)\n+\t\t\t\t}\n+\n \t\t\t\tif (!crypto.subtle) {\n \t\t\t\t\t// cannot validate, not running in a secure context\n \t\t\t\t\tthrow new Error(`'crypto.subtle' is not available so webviews will not work. This is likely because the editor is not running in a secure context (https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts).`);\nIndex: code-server/lib/vscode/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html\n===================================================================\n--- code-server.orig/lib/vscode/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html\n+++ code-server/lib/vscode/src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html\n@@ -34,6 +34,13 @@\n \t\t\t}\n \t\t\treturn start();\n \t\t}\n+\n+\t\t// It is safe to run if we are on the same host.\n+\t\tconst parent = new URL(parentOrigin)\n+\t\tif (parent.hostname === hostname) {\n+\t\t\treturn start()\n+\t\t}\n+\n \t\tif (!crypto.subtle) {\n \t\t\t// cannot validate, not running in a secure context\n \t\t\treturn sendError(new Error(`Cannot validate in current context!`));","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/coder/code-server/blob/51f90a376b42e217b38937410fe2855e0c1db87e/patches/webview.diff#L59-L95","documentation":"Thrown by the webWorkerExtensionHostIframe.html (patched in webview.diff) when window.crypto.subtle is unavailable. crypto.subtle only exists in secure contexts (https or localhost), so the iframe that hosts the extension web worker cannot validate its parent origin and refuses to start. The message explicitly points to the MDN Secure Contexts documentation.","triggerScenarios":"Loading code-server over plain http from a non-localhost host (e.g. http://10.0.0.5:8080), which is not a secure context, so crypto.subtle is undefined. The new same-host short-circuit added by webview.diff does not apply because the parent origin check happens before this throw only when hostnames match; otherwise the secure-context guard fires.","commonSituations":"Deploying code-server behind plain HTTP on a LAN/remote host without TLS; a reverse proxy terminating TLS but the browser still sees http due to misconfigured forwarding; accessing via an IP instead of localhost on http; an older browser without SubtleCrypto.","solutions":["Serve code-server over HTTPS (terminate TLS at the reverse proxy with a valid cert), which makes crypto.subtle available.","Access via http://localhost (localhost is treated as a secure context) for local development.","Ensure the reverse proxy forwards the correct scheme so the browser sees https.","Confirm the parent and iframe hostnames match so the same-host short-circuit in webview.diff can skip the crypto check."],"exampleFix":"# Serve over TLS so the browser is in a secure context\ncaddy reverse-proxy --from editor.example.com --to localhost:8080\n# or use http://localhost:8080 for local-only access","handlingStrategy":"validation","validationCode":"// Detect a secure context before relying on crypto.subtle.\nfunction canUseWebviews(): boolean {\n  return typeof crypto !== 'undefined' && typeof crypto.subtle !== 'undefined'\n}\nif (!canUseWebviews()) console.warn('Serve over HTTPS or use localhost for webviews')","typeGuard":"function isSecureContext(): boolean {\n  return typeof crypto !== 'undefined' && typeof crypto.subtle !== 'undefined'\n}","tryCatchPattern":"try {\n  startExtensionHost()\n} catch (e) {\n  if (/crypto.subtle.*not available/.test(e.message)) {\n    showUserError('Reopen over HTTPS or http://localhost to enable webviews')\n  }\n}","preventionTips":["Terminate TLS at the reverse proxy so the browser sees https.","Use http://localhost for purely local access (localhost is a secure context).","Ensure the reverse proxy forwards the correct scheme.","Match parent and iframe hostnames so the same-host short-circuit applies."],"tags":["webview","secure-context","tls","crypto","patch","browser"],"backgroundTag":null,"analyzedSha":"51f90a376b42e217b38937410fe2855e0c1db87e","analyzedAt":"2026-08-12T11:27:34.273Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}