Recently we are experiencing this problem.
When trying to upload an image file using st.file_upload, we get the 403 AxiosError.
See the attached image.
What causes this?
How can we resolve this?
Sudipta
Welcome to the Streamlit community, Sudipta! Thanks for sharing your question and the screenshot—super helpful! ![]()
The “AxiosError: Request failed with status code 403” when using st.file_uploader is a common issue, especially when deploying Streamlit apps outside of localhost (e.g., on cloud platforms, behind proxies, or with authentication enabled). The root cause is usually related to Cross-Site Request Forgery (XSRF) protection or CORS misconfiguration, which blocks the upload request for security reasons. Disabling XSRF protection often resolves the issue, but be aware this reduces security and should only be used in trusted environments. To disable XSRF protection, add the following to your .streamlit/config.toml file:
[server]
enableXsrfProtection = false
Or, run your app with the flag:
streamlit run your_app.py --server.enableXsrfProtection=false
For more details and community discussions, see this forum thread and the Streamlit documentation.
If you’re deploying behind a load balancer or proxy, ensure session stickiness is enabled and that cookies are handled correctly, as described in the Streamlit architecture docs. Also, check that your deployment platform isn’t stripping cookies or headers required for file uploads.
Sources:
An AxiosError: Request failed with status code 403 on st.file_uploader (PUT /_stcore/upload_file/...) is almost always caused by Cross-Site Request Forgery (enableXsrfProtection) cookie/header mismatch behind a reverse proxy or iframe, or an upstream WAF (Cloudflare / Nginx / AWS ALB) blocking PUT multipart uploads.
Normal widget clicks travel over the existing /_stcore/stream WebSocket connection. File uploads, however, send a separate HTTP PUT request via Axios to /_stcore/upload_file/<session_id>/<file_id> with an X-XSRFToken header read from the _streamlit_xsrf cookie.
Host / Origin headers, or routes the HTTP PUT to a different container replica than the one holding the WebSocket session (missing sticky sessions), Tornado rejects the upload with 403 Forbidden..streamlit/config.toml: ```toml*(If setting `enableXsrfProtection = false` immediately resolves the `403`, update your Nginx/ALB proxy to forward `Host`, `X-Forwarded-Proto`, and `Cookie` headers intact so you can turn XSRF protection back on safely.)*
If Running Multiple Replicas: Enable cookie/IP sticky sessions (ip_hash in Nginx or ALB stickiness) so /_stcore/upload_file lands on the exact pod holding the active /_stcore/stream WebSocket.