You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On Windows, a backend provider that is a .cmd or .bat file is accepted by discovery, resolves to a valid provider id, and answers the info request successfully — but every deploy fails, because stage_provider copies the provider into a temp directory and unconditionally names the copy provider.exe. CreateProcess then refuses the batch script it finds behind that .exe name with os error 216.
The two halves of the code disagree with each other. provider_id_from_filename deliberately strips .exe, .bat and .cmd, and its doc comment says so explicitly — so script providers are intended to be discoverable. stage_provider then destroys the extension that Windows needs to dispatch them.
Environment
Buzz Desktop v0.5.23
Windows 11
Provider installed as a .cmd file on PATH (e.g. C:\Users\<user>\.local\bin\)
Steps to reproduce
Create buzz-backend-example.cmd somewhere on PATH (for example %USERPROFILE%\.local\bin\). A minimal one that satisfies the strict info schema is enough:
(The info response is validated against a closed allowlist of exactly these six keys, with protocol_version = 1 and config_schema an object.)
Restart Buzz Desktop and open the agent creation flow. The provider appears in the Where to run dropdown as example, and the info request against it succeeds — the entry looks healthy.
Create an agent using that provider and deploy it.
Expected
Either the deploy works — the provider is discoverable, resolvable and answers info, so nothing in the UI suggests it cannot be used — or the provider is rejected at discovery time with an explicit reason.
Actual
The deploy fails at spawn:
failed to spawn C:\Users\<user>\AppData\Local\Temp\buzz-provider-XXXXXX\provider.exe: This version of %1 is not compatible with the version of Windows you're running. Check your computer's system information and then contact the software publisher. (os error 216)
The provider is never given a chance to run. The failure is in process creation, before any op is written to stdin.
Root cause
All citations are against desktop/src-tauri/src/managed_agents/backend.rs at commit 779af8886caae1317b4de962082429867ab61503.
1. Script providers are intentionally discoverable.provider_id_from_filename strips all three Windows extensions, and its doc comment states the reason:
/// Derive a provider id from the filename Tauri stages at runtime. Tauri/// removes its target-triple suffix while copying an external binary, but on/// Windows leaves the executable/script extension, which is not part of the/// provider id.fn provider_id_from_filename(name:&str) -> Option<&str>{let raw = name.strip_prefix("buzz-backend-")?;let id = [".exe",".bat",".cmd"].into_iter()// ...
So buzz-backend-example.cmd yields the id example, which passes the [a-z0-9][a-z0-9_-]* check in resolve_provider_binary and resolves normally.
2. Nothing filters it out.is_executable returns true unconditionally on non-unix, so the .cmd passes the executability gate in discover_provider_candidates (which scans PATH, the app exe directory, and ~/.local/bin).
3. Staging discards the extension.stage_provider hard-codes the suffix:
The copy is then made read-only and held open under a share-mode guard before either invocation. Whatever the source file was, the thing that actually gets spawned is named provider.exe — and CreateProcess dispatches on the extension, so a batch script behind an .exe name is rejected as a malformed PE image.
Why it is confusing
The info path and the deploy path do not agree on what they execute.
The info request issued for the Where to run dropdown calls invoke_provider on the original file (desktop/src-tauri/src/commands/agent_providers.rs:42). buzz-backend-example.cmd still has its extension there, so Windows dispatches it correctly and it answers.
provider_deploy calls stage_provider first and runs everything — including its own info negotiation — against the staged provider.exe.
So the provider appears healthy in the UI right up to the moment a user commits to creating an agent with it, and the error that finally surfaces names a temp path and a file the user never created.
There is also a standing disagreement inside main about which way this should go. #4289 added the extension strip that makes script providers discoverable; the still-open #3310 argues the opposite direction — narrow the Windows allowlist to exe/com and reject script-shaped providers outright, on the grounds that routing them through cmd.exe puts a shell-quoting surface in front of a code path that pipes an agent's private key over stdin. Neither of those touches stage_provider, which is where the current contradiction actually bites.
Suggested fixes
Offered as options, not a prescription:
(a) Preserve the original extension when staging on Windows. Take the suffix from binary instead of hard-coding ".exe". CreateProcess already routes .cmd/.bat through cmd.exe when the extension is present, so this alone is sufficient to make script providers work.
(b) Invoke staged script providers explicitly through cmd.exe /c rather than relying on implicit dispatch — still with the extension preserved, since cmd.exe /c against a file named provider.exe fails the same way.
(c) If only PE binaries are supportable on Windows, reject .cmd/.bat at discovery time with an explicit error, instead of stripping their extensions and letting them appear to work. This is the direction fix(desktop): make backend providers runnable on Windows #3310 proposes, with the stdin/secret-handling rationale noted above; it would also mean removing .bat/.cmd from provider_id_from_filename so the two decisions stop contradicting each other.
Whichever direction is chosen, the useful invariant is that discovery and deploy should agree: a provider that reaches the Where to run dropdown and answers info should not be one that can never be spawned.
Workaround
For anyone hitting this now: ship a small native .exe shim named buzz-backend-<id>.exe that re-executes the real script with inherited stdio. The shim must reference the script by absolute path — the staged copy lives alone in a fresh temp directory, so nothing resolves relative to the shim's own location at runtime, and neither does anything else that was sitting next to the original file.
Summary
On Windows, a backend provider that is a
.cmdor.batfile is accepted by discovery, resolves to a valid provider id, and answers theinforequest successfully — but every deploy fails, becausestage_providercopies the provider into a temp directory and unconditionally names the copyprovider.exe.CreateProcessthen refuses the batch script it finds behind that.exename withos error 216.The two halves of the code disagree with each other.
provider_id_from_filenamedeliberately strips.exe,.batand.cmd, and its doc comment says so explicitly — so script providers are intended to be discoverable.stage_providerthen destroys the extension that Windows needs to dispatch them.Environment
.cmdfile onPATH(e.g.C:\Users\<user>\.local\bin\)Steps to reproduce
Create
buzz-backend-example.cmdsomewhere onPATH(for example%USERPROFILE%\.local\bin\). A minimal one that satisfies the strictinfoschema is enough:(The
inforesponse is validated against a closed allowlist of exactly these six keys, withprotocol_version= 1 andconfig_schemaan object.)Restart Buzz Desktop and open the agent creation flow. The provider appears in the Where to run dropdown as
example, and theinforequest against it succeeds — the entry looks healthy.Create an agent using that provider and deploy it.
Expected
Either the deploy works — the provider is discoverable, resolvable and answers
info, so nothing in the UI suggests it cannot be used — or the provider is rejected at discovery time with an explicit reason.Actual
The deploy fails at spawn:
The provider is never given a chance to run. The failure is in process creation, before any
opis written to stdin.Root cause
All citations are against
desktop/src-tauri/src/managed_agents/backend.rsat commit779af8886caae1317b4de962082429867ab61503.1. Script providers are intentionally discoverable.
provider_id_from_filenamestrips all three Windows extensions, and its doc comment states the reason:So
buzz-backend-example.cmdyields the idexample, which passes the[a-z0-9][a-z0-9_-]*check inresolve_provider_binaryand resolves normally.2. Nothing filters it out.
is_executablereturnstrueunconditionally on non-unix, so the.cmdpasses the executability gate indiscover_provider_candidates(which scansPATH, the app exe directory, and~/.local/bin).3. Staging discards the extension.
stage_providerhard-codes the suffix:The copy is then made read-only and held open under a share-mode guard before either invocation. Whatever the source file was, the thing that actually gets spawned is named
provider.exe— andCreateProcessdispatches on the extension, so a batch script behind an.exename is rejected as a malformed PE image.Why it is confusing
The
infopath and the deploy path do not agree on what they execute.inforequest issued for the Where to run dropdown callsinvoke_provideron the original file (desktop/src-tauri/src/commands/agent_providers.rs:42).buzz-backend-example.cmdstill has its extension there, so Windows dispatches it correctly and it answers.provider_deploycallsstage_providerfirst and runs everything — including its owninfonegotiation — against the stagedprovider.exe.So the provider appears healthy in the UI right up to the moment a user commits to creating an agent with it, and the error that finally surfaces names a temp path and a file the user never created.
There is also a standing disagreement inside
mainabout which way this should go. #4289 added the extension strip that makes script providers discoverable; the still-open #3310 argues the opposite direction — narrow the Windows allowlist toexe/comand reject script-shaped providers outright, on the grounds that routing them throughcmd.exeputs a shell-quoting surface in front of a code path that pipes an agent's private key over stdin. Neither of those touchesstage_provider, which is where the current contradiction actually bites.Suggested fixes
Offered as options, not a prescription:
binaryinstead of hard-coding".exe".CreateProcessalready routes.cmd/.batthroughcmd.exewhen the extension is present, so this alone is sufficient to make script providers work.cmd.exe /crather than relying on implicit dispatch — still with the extension preserved, sincecmd.exe /cagainst a file namedprovider.exefails the same way..cmd/.batat discovery time with an explicit error, instead of stripping their extensions and letting them appear to work. This is the direction fix(desktop): make backend providers runnable on Windows #3310 proposes, with the stdin/secret-handling rationale noted above; it would also mean removing.bat/.cmdfromprovider_id_from_filenameso the two decisions stop contradicting each other.Whichever direction is chosen, the useful invariant is that discovery and deploy should agree: a provider that reaches the Where to run dropdown and answers
infoshould not be one that can never be spawned.Workaround
For anyone hitting this now: ship a small native
.exeshim namedbuzz-backend-<id>.exethat re-executes the real script with inherited stdio. The shim must reference the script by absolute path — the staged copy lives alone in a fresh temp directory, so nothing resolves relative to the shim's own location at runtime, and neither does anything else that was sitting next to the original file.