Skip to content

[Bug]: Windows: html_preview/html_render fail with "Internal error" when Group Policy blocks chrome-headless-shell.exe in %USERPROFILE%\.t3\tools #21686

Closed

Description

@TomLeppens99

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. Use T3 Code (Beta) desktop on a managed Windows PC where Group Policy (AppLocker / Software Restriction Policies) only allows executables from approved locations. That's common in corporate and university environments. On this PC, T3 Code itself is installed in an approved folder (C:\GBW_MyPrograms\t3-code-desktop\).
  2. Have an agent call html_preview or html_render.
  3. T3 downloads Chrome for Testing's headless shell to %USERPROFILE%\.t3\tools\chrome-headless-shell\win64\<version>\chrome-headless-shell.exe and tries to spawn it.

Expected behavior

The preview browser should launch from a location the PC's policy already allows, for example:

  • next to the installed T3 Code app (<install dir>\resources\...), which policy already trusts because T3 Code itself runs from there; and/or
  • a user-configurable path, such as an env var or setting (T3CODE_PREVIEW_BROWSER_PATH) or a configurable tools directory, so it can point to an approved location or an already-installed Chrome/Edge.

When the launch is blocked, T3 should report a clear error that says Windows policy blocked the browser and where it is installed.

Actual behavior

Windows blocks the executable because it is unsigned and runs from the user profile ("This program is blocked by group policy"). Node's spawn fails with spawn UNKNOWN, and both html_preview and html_render return only Internal error. The agent then falls back to Mermaid/text and tells the user the "preview service returned an internal error".

The tools directory is always path.join(baseDir, "tools", "chrome-headless-shell", ...). The only way to change it is T3CODE_HOME, and that moves all of T3's state, not just the browser.

Impact

Major degradation or frequent failure: inline HTML visuals never work on policy-managed Windows machines.

Version or commit

T3 Code (Beta) desktop 0.1.0; chrome-headless-shell 154.0.8037.92

Environment

Windows 11 Enterprise 10.0.26200 (domain-managed, AppLocker/SRP path rules); Claude Code provider

Logs or stack traces

HtmlRender.preview / HtmlRender.publish failed:
Error: spawn UNKNOWN
    at ChildProcess.spawn (node:internal/child_process:458:11)
    at Module.spawn (node:child_process:813:9)
    at headlessChrome.captureHtmlScreenshot (.../resources/server.asar/apps/server/dist/binCli-*.mjs)
    at HtmlRender.preview (...)
    at McpServer.@effect/mcp/2025-06-18/tools/call

# Running the exe directly from PowerShell:
This command cannot be run due to the error: This program is blocked by group policy.
Get-AuthenticodeSignature chrome-headless-shell.exe -> Status: NotSigned

Workaround

Move the browser into an approved folder and leave a directory junction at the path T3 expects. AppLocker evaluates the resolved path, so the launch is allowed:

Move-Item "$env:USERPROFILE\.t3\tools\chrome-headless-shell" "C:\<approved dir>\t3-chrome-headless-shell"
New-Item -ItemType Junction -Path "$env:USERPROFILE\.t3\tools\chrome-headless-shell" -Target "C:\<approved dir>\t3-chrome-headless-shell"

After that, html_preview and html_render work. A T3 update or re-install of the tools folder could break this, so a supported option would be better.

Activity

  1. juliusmarminge commented on Oct 19, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Accepted as a bug, scoped to the error message. Group Policy blocking an unsigned browser is your machine's policy, and the junction workaround is fine for now.

    On main, a browser that starts and then fails is reported clearly. A failed spawn is caught only as a typed error (headlessChrome.ts:193-232). Node throws some spawn errors, including spawn UNKNOWN, straight out of the spawn call. That escapes as an unexpected failure, which reaches the agent as "Internal error" instead of the named message (headlessChrome.ts:25-33). #16872 improved messages for a browser that exits, not for this case. The Tailscale probe already guards the same kind of throw (tailscale.ts:226-231).

    Choosing a system Chrome or Edge, or another browser path, is tracked in Ideas discussion #17465. Please add your policy use case there.

  2. added
    acceptedfeature request accepted
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 19, 2026
  3. t3dotgg commented on Oct 21, 2026

    @t3dotgg
    Member

    Note

    🤖 Claude Opus 5.5 responding on behalf of Theo

    Thanks for the report. One part of this is fixed on main in #22895: a blocked browser start now reports that the browser could not be started instead of "Internal error". Please test on the nightly built from main on 2026-10-21, or on the next stable release. One part is still open: naming the blocked browser location or letting you choose another one. If that part still matters to you, please open a new issue for that part only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions