Bad message: o[r] is undefined floating(?) bug

Streamlit version: 1.30.0
Python3 version: 3.11.6
Browsers: Firefox 121.0.1 on Ubuntu 23.10, Chromium 121.0.6167.85 snap on Ubuntu 23.10

This code snippet used to work up until yesterday, and now pressing any of the buttons in col1 gives a “Bad message format: o[r] is undefined” (in FF) or “Bad Message Format: Cannot read properties of undefined (reading ‘setIn’)” (in Chromium). Please help.

Edit: i probably should try modifying one pre-made form instead of recreating them every button press, but it used to work this way anyway.

Edit 2: added more info about the system.

WARNING: programmer horror ahead.

import streamlit as st
from pathlib import Path
from os import W_OK, R_OK, access, makedirs, listdir
import syslog

INIDIR = '/etc/inidir/'



def init():
        st.set_page_config(layout="wide")
	
	if 'confpage' not in st.session_state.keys():
		st.session_state['confpage'] = {}
	
	if 'inidir' not in st.session_state.confpage.keys():
		st.session_state.confpage['inidir'] = INIDIR

def list_sources(_dir=INIDIR) -> list: #returns a list of dicts like {'savename':'', 'savetime':'', 'filename':''}
	_dir = Path(_dir)
	if not _dir.is_dir():
		msg = f"{_dir} is not accessible"
		syslog.syslog(syslog.LOG_ERR, msg)
		raise FileNotFoundError(msg)
	L = [x for x in listdir(_dir) if (_dir/x).is_file() and ''.join(x[-3::]) == 'ini']
	out = []
	for f in L:
		try:
			with (_dir/f).open('r') as F:
				savetime = ''
				savename = ''
				for line in F.read().split('\n'):
					if 'savetime: ' in line and line.strip()[0] == '#':
						savetime = line.strip().split(': ')[1]
					if 'savename: ' in line and line.strip()[0] == '#':
						savename = line.strip().split(': ')[1]
						break
				out.append({'savename':savename, 'savetime':savetime, 'filename':str(_dir/f)})
				
		except Exception as e:
			syslog.syslog(syslog.LOG_CRIT, f' {_dir/f} file is inaccessible, more info:\n {str(e)}\n')
			raise e
	return out

def _create_form(formbox: st.container, filepath: str):
	try:
		data = load_from_file(filepath)
		formbox.empty()
		with formbox:
			_form = st.form("yet-another-form")
	except Exception as e:
		syslog.syslog(syslog.LOG_CRIT, f'Error:\n {str(e)}\n')
		raise e
	else:
		with _form:
			if '/' in filepath:
				st.caption(f"File currently edited: {filepath.split('/')[-1]}")
			else:
				st.caption(f"File currently edited: {filepath}")
			st.text_input(label = "Savename", value=data['old_savename'] if 'old_savename' in data.keys() else "", key='savename')
			st.text_input(label = "Receiver's address", value = data['old_recv_addr'], key='recv_addr')
			for i in range(1, data['count']):
				if f'old_server_addr{i}' in data.keys():
					st.text_input(label=f'Server Address {i}', value=data[f'old_server_addr{i}'], key=f'server_addr{i}') 
					st.text_input(label=f'Server Port {i}', value=data[f'old_server_port{i}'], key=f'server_port{i}') 
				else:
					st.text_input(label=f'Server Address {i}', key=f'server_addr{i}') 
					st.text_input(label=f'Server Port {i}', key=f'server_port{i}') 
			submit = st.form_submit_button(label='Save', on_click=_save_parser, kwargs={})

def render():
        st.title('Page Title')
	st.header('page header')
	
	filelist = list_sources(st.session_state.confpage['inidir']) #[{'savename':'', 'savetime':'', 'filename':''}, {...}] 
	
	col1, col2, col3= st.columns([0.25, 0.375, 0.375], gap='large')
	with col1:
		col1.subheader("Choose the file to edit")
		filebox = col1.container(height=600)
	
	formbox = col2.container()
	
	col3.empty()
	with col3:
		col3.subheader(f"Operation Status:")
		st.write("Placeholder")
	
	
	
	for source in filelist:
		filebox.button(f"{source['savename']};{source['savetime']} ({source['filename']})", on_click=_create_form, kwargs={'formbox':formbox, 'filepath':source['filename']}) 

init()
render()

Hello @RCZ00,

Instead of calling _create_form directly within the button’s on_click , set a session state variable indicating which file was selected, and then check this state in your main application logic to determine which form to display.

def render():
    # Existing setup code...
    for source in filelist:
        if filebox.button(f"{source['savename']};{source['savetime']} ({source['filename']})"):
            st.session_state['selected_file'] = source['filename']

    if 'selected_file' in st.session_state:
        _create_form(formbox, st.session_state['selected_file'])
1 Like

Thank you! That worked, but it’s a bit counterintuitive, especially with the streamlit documentation on buttons stating my way of using callbacks as valid. Can you elaborate, please, as to why the way i used wasn’t working?

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.