streamlit: st.file_uploader returns HTTP code 400 with invalid session_id when deployed on Kubernetes

Summary

In my Streamlit app deployed in a standalone Docker container, local files can be uploaded via st.file_uploader without any problems. However, for the same app deployed on Kubernetes cluster in multiple replicas setting, st.file_uploader randomly returns HTTP status code 400 with an error message like:

400: Invalid session_id: ‘1d319bd4-b1dc-4149-bfb2-24cdd48f3982’

obraz

The behaviour is non-deterministic - reloading (sometimes more than once) the browser tab helps.

Steps to reproduce

  • Deploy a Streamlit app on Kubernetes with multiple replicas
  • Run the app in a browser
  • Select any file in st.file_uploader’s window.
  • If the error doesn’t occur, reload the browser tab and try again.

Code snippet:

st.file_uploader("Choose a file")

Expected behavior:

st.file_uploader works exactly the same way in a single Docker container and when deployed on Kubernetes cluster with multiple replicas.

Debug info

  • Streamlit version: 1.0.0
  • Python version: 3.7.8
  • continuumio/miniconda3:4.9.2 Docker image

Additional information

The problem was reported previously in a comment https://github.com/streamlit/streamlit/issues/2803#issuecomment-948079579 , but without specific details.

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 4
  • Comments: 15

Most upvoted comments

still facing this issue…

Hi @JT-R, this one might be a bit tricky to solve given that the file_uploader is by its nature a stateful widget. I haven’t spent any time trying to reproduce the issue myself, but I’m fairly certain what’s going on here is that the /upload endpoint that the streamlit frontend attempts to use is having its request routed to a different node than the one that the frontend is connected to via websocket.

One possible solution to this would be to turn on some form of sticky sessions / sticky request routing in your deployment to ensure that the server that receives the /upload request is the same one that the frontend initially connected to.

In the long run, we’ll be thinking about these types of problems given that they’ll start to come up more naturally as people build streamlit apps that need to scale to more and more users. In the short term, however, it’s unlikely that we’ll be able to address this soon as doing so would require a substantial overhaul to how the file uploader widget works, so your best bet to fix this soon would likely be to see if sticky sessions are possible for your use-case

i am trying with docker and i am having the same problem, does someone know what might cause this in Docker??

IF you are using ALB as your ingress you can find that pretty helpful:

alb.ingress.kubernetes.io/target-group-attributes: "stickiness.enabled=true,stickiness.type=lb_cookie,stickiness.lb_cookie.duration_seconds=600",

https://stackoverflow.com/a/69421431

IF you are using ALB as your ingress you can find that pretty helpful:

alb.ingress.kubernetes.io/target-group-attributes: "stickiness.enabled=true,stickiness.type=lb_cookie,stickiness.lb_cookie.duration_seconds=600",

https://stackoverflow.com/a/69421431

This actually worked!! use nginx and set-cookie, and then add this as well to ingress.

I have same error after upgrading to latest version, 1.29.0. I deploy my app on azure, and I already set the session affinity on for this app. image Any advice I can do more?

Hey @vdonato, thanks for a detailed response! We’re going to try out single instances for now and if the internal app starts getting a lot of traffic we will look into sticky sessions. Also will keep an eye out for the shared location solution. Cheers!

Hey @nishant-emburse,

Coincidentally, we’re currently working on a project that will eventually enable users to configure pieces of the file uploader widget so that it can operate more smoothly in multi-instance deployments. We’ve recently worked on several projects with a similar theme of making the Streamlit internals more configurable, but the piece we’re missing before we’ll be able to expose all of these things publicly is a more advanced config system. See this comment on a similar issue for more context: https://github.com/streamlit/streamlit/issues/5849#issuecomment-1510010145.

That being said, even once everything is available for public use, I’d probably still recommend relying on session affinity to get st.file_uploader to work as expected in most multi-instance deployments.

The difficulty with getting a widget like the file uploader to work correctly when there are several streamlit server instances (assuming no session affinity) is that the file upload, which happens via HTTP as sending large files via websocket comes with its own set of difficulties, may land on a different server than the one the browser has a websocket connection to. As a result of this, a solution would require either

  1. Streamlit servers to be able to talk to each other to pass files around
    • This would require some nontrivial configuration outside of streamlit itself to enable service discovery. It also feels somewhat hacky
  2. A way to upload files to a shared location (like AWS S3 or some other intermediary service) rather than directly to an individual streamlit server
    • This is what the in-progress changes to the file uploader widget will enable. It feels like the more “correct” solution to me

The difficulty with both solutions is that they’re far from “automatic” – developers will have to do a nontrivial amount of work outside of Streamlit to get everything set up. While some users will certainly have use cases where it’s worth the effort to do this (including us at Snowflake, which is why we’re building this configurability into the file uploader to begin with), I’d imagine that it wouldn’t be worth the effort compared to just turning on sticky sessions in most situations.