5 min read

Fix: Cowork's file_upload Tool Returns 'Not Allowed' on Every Origin

Cowork’s Chrome connector exposes a file_upload tool for uploading local files to web form inputs. Every call fails with the same CDP error:

Failed to upload file(s): {"code":-32000,"message":"Not allowed"}

This blocks any workflow that needs to put a local file into a web form: uploading photos to Etsy, attaching documents to portals, submitting files to any site.

The Fix

Go to chrome://extensions, find the Claude in Chrome extension, click Details, and enable “Allow access to file URLs”.

The file_upload tool works immediately after with no restart needed.

How we got here

The fix is one setting. Finding it took two rounds of systematic diagnostic testing and a fair amount of wrong assumptions that had to be corrected along the way.

Round 1: Confirming the tool is broken

The first diagnostic enumerated all 18 Chrome tools available through the MCP bridge and tested file_upload on a page hosted on google.com. It failed with -32000 "Not allowed". A prior bug report (#32179) had attributed this to a Chrome security policy specific to google.com, which seemed plausible, since Google does enforce tighter restrictions on its own domains.

Two alternative upload methods were also tested. The upload_image tool failed; it’s designed for screenshot blobs within the extension’s memory, not files from disk. The JavaScript DataTransfer API, injected via javascript_tool, succeeded. That gave us a workaround, but one with significant limitations: you can only inject content already available as a string or blob in the browser context (no filesystem access), and the events fire with isTrusted: false, which Google services and other security-conscious sites silently reject.

Round 2: Proving it’s universal

The second round tested file_upload on multiple real HTTPS origins to determine if the google.com attribution was correct:

OriginResult
the-internet.herokuapp.com-32000 "Not allowed"
example.com-32000 "Not allowed"
google.com-32000 "Not allowed"

Same error everywhere. The domain doesn’t matter. The file path format doesn’t matter. Windows backslashes, forward slashes, known system files, all fail identically.

Wrong assumptions we had to correct

At this point we had several working hypotheses. Validating them against primary sources before writing the bug report turned up problems with most of them:

“The extension may lack the debugger permission for CDP access.” Wrong. Other CDP-dependent tools (read_page, form_input, javascript_tool) work correctly. The permission is present and functional.

“Chrome is blocking CDP on certain origins.” Partially wrong. The error is universal across all origins, not domain-specific. This was the key correction to #32179’s analysis.

“The extension is missing the Page.setInterceptFileChooserDialog handshake.” This was our strongest hypothesis. Chromium bug #928255 documented that Chrome 72+ requires intercepting the file chooser dialog and using the resulting backendNodeId before calling DOM.setFileInputFiles. The mcp-chrome project (nicholasoxford/mcp-chrome, repo no longer available) had successfully implemented this approach. It fit the evidence perfectly, and it was wrong.

“This is a code bug in the extension.” Also wrong. The implementation is fine. It just needs a permission that isn’t enabled by default.

Round 3: The actual answer

After enabling “Allow access to file URLs” in the extension settings (along with “Collect errors” for diagnostics), re-running the exact same tests produced completely different results:

OriginResult
the-internet.herokuapp.comUpload succeeded
example.comUpload succeeded, content verified

The CDP DOM.setFileInputFiles call that was returning -32000 completed without error. FileReader confirmed full file content transfer, with 1,053 bytes read correctly from a test file.

The -32000 "Not allowed" error wasn’t caused by a wrong CDP call sequence or a missing browser handshake. It was a Chrome extension permission. Without “Allow access to file URLs” enabled, the extension’s CDP calls that reference local file paths get blocked at the Chrome level. The implementation was correct all along.

Second gotcha: Use Windows paths, not VM paths

Even after enabling the permission, uploads can still silently fail if the agent passes its own internal file path instead of the Windows host path.

Cowork runs Claude inside a Linux VM, but Chrome runs on the Windows host. The file_upload tool passes paths straight through to Chrome via CDP’s DOM.setFileInputFiles, which resolves them against the host filesystem. The VM’s mount paths don’t exist from Chrome’s perspective.

This works:

file_upload(paths=["C:\\Users\\Bryce\\Projects\\portfolio-scout\\photo.jpg"], ...)

This doesn’t:

file_upload(paths=["/sessions/zen-brave-gates/mnt/portfolio-scout/photo.jpg"], ...)

The VM mounts the user’s selected folder at /sessions/<id>/mnt/<folder>, but when calling file_upload you need the original Windows path (C:\Users\<user>\...\<folder>) because that’s where Chrome is actually reading from. If the upload silently produces no result or the target site reports an empty file, this is likely why.

Status

The issue (#32561) is closed. The fix is a user-accessible setting, but since file_upload is non-functional without it, it probably should be either enabled by default or documented in the Cowork setup guide. The related duplicate chain (#32179 → #30861, #30112, #28067) tracks the separate VM network allowlist problem and remains open.

I'm an independent engineer (ex-eBay) who designs and builds production AI systems. I work deep in the Claude Code and MCP ecosystem, document what I find, and take on contract work. Currently taking on projects. Get in touch .