St.file_uploader keeps calling the callback function passed into the 'on_change' parameter on every other widget change

Streamlit v1.3.0

I only want the file_uploader to run the callback function when I remove any file or upload any new file to the file_uploader widget. But now I’m having this issue where it keeps calling the ‘on_change’ callback function even though I didn’t remove or upload any file. The way to trigger this is just to change any other widget’s value (e.g. the button in the example code below).

But I know I’m actually changing it’s value when I tried to access it to copy the file to a temporary folder to use it to do something. So I tried to use and also deepcopy(video_file) to try to avoid changing the value of the file_uploader, but still in vain. Please help.

import streamlit as st
import shutil
import os
from copy import deepcopy
from pathlib import Path

TEMP_DIR = Path('tmp/extracted')

def dummy_cb():

video_file = st.sidebar.file_uploader(
    "Upload a video", type=['mp4', 'mov', 'avi', 'asf', 'm4v'],
    key='video_file_uploader', on_change=dummy_cb)

if video_file is None:

# use this to avoid keep calling the file_uploader's callback
# NOTE: still not helping...
uploaded_video = deepcopy(video_file)

video_path = str(TEMP_DIR /

print("Copying file")
if TEMP_DIR.exists():
print(f"{video_path = }")
with open(video_path, 'wb') as f:

# seeking is also not helping"options", (1, 2), key='dummy_options')
1 Like

I settled with a workaround by performing all the necessary callbacks within the if video_file is None statement. This works well for accepting a single upload but probably not multiple files.

if video_file is None:"Resetting states for uploaded video")
    # reset and remove the TEMP_DIR if there's no uploaded file
    # to ensure the app only reads the new uploaded file
    if TEMP_DIR.exists():

# using str to ensure readable by and cv2
video_path = str(TEMP_DIR /

if not os.path.exists(video_path):
    # only creates it if not exists, to speed up the process when
    # there is any widget changes besides the st.file_uploader
    logger.debug(f"{video_path = }")
    with st.spinner("Copying video to a temporary directory ..."):
        with open(video_path, 'wb') as f:
1 Like

Hi, I am having the same issue. I’ve created a demo app to replicate the issue so that it can hopefully be addressed sooner.

import streamlit as st

def uploader_callback():
    print('Uploaded file')

    label='File uploader',

st.text_input(label='Textbox 1', key='first')

Bug: If another widget gets updated, e.g. st.text_input, the callback function passed into ‘on_change’ of st.file_uploader gets reran even if the file has remained the same.

Desired: st.file_uploader on_change to behave as it should - only running when the value of st.file_uploader is changed