### Software versions
Python version : 3.9.16 (main, Mar 8 2023, 10:39…:24) [MSC v.1916 64 bit (AMD64)]
IPython version : 8.12.0
Tornado version : 6.2
Bokeh version : 3.1.1
BokehJS static path : C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\server\static
node.js version : (not installed)
npm version : (not installed)
Operating system : Windows-10-10.0.22621-SP0
### Browser name and version
Firefox 114.0.2 (64-bit)
### Expected behavior
Within a Bokeh server application, I have a layout in which I render a plot which is to be exchanged when a button is pressed. In between, a loading screen (a plot with just a label that says "Loading") is to be displayed.
### Observed behavior
It works, but each time the exchange is made, it produces an error like
`bokeh.core.serialization.DeserializationError: can't resolve reference 'p1074'`
with the reference being the last plot.
### Example code
```Python
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, Label, Button
from bokeh.layouts import column
from random import *
def loading_pic(width: int = 500, height: int = 500) -> figure:
plot = figure(x_range=(0,width), y_range=(0,height), width=width, height=height, tools='')
pos_x = width/2
pos_y = height/2
label_size = min(height/4, width/4)
label_size_str = str(label_size)+'px'
loading_label = Label(x=pos_x, y=pos_y, text='Loading', text_font_size = label_size_str,
text_align='center', text_baseline='middle')
plot.add_layout(loading_label)
plot.xaxis.visible = False
plot.yaxis.visible = False
plot.xgrid.grid_line_color = None
plot.ygrid.grid_line_color = None
return plot
def random_coords(maximum: float = 500, amount: int = 10000) -> ColumnDataSource:
data = ColumnDataSource()
data.data['x'] = [random()*maximum for i in range(amount)]
data.data['y'] = [random()*maximum for i in range(amount)]
return data
class MyPlot:
def __init__(self, data: ColumnDataSource):
self.plot = figure(x_range=(0,500), y_range=(0,500), width=500, height=500)
self.plot.circle(source=data, x='x', y='y')
class MyFrame:
def __init__(self):
self._loading = loading_pic()
self._loading_container = column(self._loading)
self._render_container = column(column())
self._render_container.visible = False
self.layout = column(self._loading_container, self._render_container)
def display_loading(self) -> None:
curdoc().hold("combine")
self._loading_container.visible = True
self._render_container.visible = False
curdoc().unhold()
def plot(self) -> None:
curdoc().hold("combine")
data = random_coords()
self._my_plot = MyPlot(data)
print("plot:", self._my_plot.plot)
self._render_container.children[0] = self._my_plot.plot
self._loading_container.visible = False
self._render_container.visible = True
curdoc().unhold()
def plot_delayed(self, event) -> None:
self.display_loading()
curdoc().add_next_tick_callback(self.plot)
my_frame = MyFrame()
button = Button(label='Create')
button.on_event('button_click', my_frame.plot_delayed)
layout = column(my_frame.layout, button)
curdoc().add_root(layout)
```
### Additional Info
To trigger the bug, the "Create" button has to be hit *twice*. The first click works fine, but each click afterwards produces the error.
In order to make my code example quicker to read, I tried to reduce it further, especially by removing the loading screen. The bug stops to exist at some point. The quickest way to make it disappear is by removing the lines which make the "container" objects visible or invisible.
I already posted the issue in the Bokeh forums (initially in a different form) and we had some discussion regarding it:
https://discourse.bokeh.org/t/bug-with-deserializationerror-when-changing-content-layout-in-bokeh-3-1-1/10566/8
[And I also have another post on SO: [https://stackoverflow.com/questions/76506289/bokeh-3-1-1-deserializationerror-when-changing-layout-content](https://stackoverflow.com/questions/76506289/bokeh-3-1-1-deserializationerror-when-changing-layout-content) ]
Note that while in this reduced example, I could easily fix the code by replacing the source of the plot instead of the whole plot at all, I dislike this strategy in the big picture. The actual plots I am using have a lot of elements, and changing their sources seems error-prone to me, possible carrying over artifacts from old plots.
Also, my actual code (which was the base for the reduced code) worked without this error under Bokeh 2.4.3, and it occured only after updating to Bokeh 3.1.1.
### Stack traceback in Anaconda Powershell
```
2023-06-23 11:44:24,383 error handling message
message: Message 'PATCH-DOC' content: {'events': [{'kind': 'ModelChanged', 'model': {'id': 'p1074'}, 'attr': 'inner_width', 'new': 0}, {'kind': 'ModelChanged', 'model': {'id': 'p1074'}, 'attr': 'inner_height', 'new': 0}, {'kind': 'ModelChanged', 'model': {'id': 'p1074'}, 'attr': 'outer_width', 'new': 0}, {'kind': 'ModelChanged', 'model': {'id': 'p1074'}, 'attr': 'outer_height', 'new': 0}]}
error: DeserializationError("can't resolve reference 'p1074'")
Traceback (most recent call last):
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\server\protocol_handler.py", line 97, in handle
work = await handler(message, connection)
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\server\session.py", line 94, in _needs_document_lock_wrapper
result = func(self, *args, **kwargs)
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\server\session.py", line 288, in _handle_patch
message.apply_to_document(self.document, self)
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\protocol\messages\patch_doc.py", line 104, in apply_to_document
invoke_with_curdoc(doc, lambda: doc.apply_json_patch(self.payload, setter=setter))
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\document\callbacks.py", line 443, in invoke_with_curdoc
return f()
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\protocol\messages\patch_doc.py", line 104, in <lambda>
invoke_with_curdoc(doc, lambda: doc.apply_json_patch(self.payload, setter=setter))
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\document\document.py", line 369, in apply_json_patch
patch: PatchJson = deserializer.deserialize(patch_json)
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\core\serialization.py", line 501, in deserialize
return self.decode(obj.content, obj.buffers)
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\core\serialization.py", line 516, in decode
return self._decode(obj)
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\core\serialization.py", line 557, in _decode
return {key: self._decode(val) for key, val in obj.items()}
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\core\serialization.py", line 557, in <dictcomp>
return {key: self._decode(val) for key, val in obj.items()}
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\core\serialization.py", line 559, in _decode
return [self._decode(entry) for entry in obj]
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\core\serialization.py", line 559, in <listcomp>
return [self._decode(entry) for entry in obj]
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\core\serialization.py", line 557, in _decode
return {key: self._decode(val) for key, val in obj.items()}
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\core\serialization.py", line 557, in <dictcomp>
return {key: self._decode(val) for key, val in obj.items()}
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\core\serialization.py", line 555, in _decode
return self._decode_ref(cast(Ref, obj))
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\core\serialization.py", line 569, in _decode_ref
self.error(f"can't resolve reference '{id}'")
File "C:\Users\<my username>\anaconda3\lib\site-packages\bokeh\core\serialization.py", line 717, in error
raise DeserializationError(message)
bokeh.core.serialization.DeserializationError: can't resolve reference 'p1074'
```