You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ValueError(“Invalid value”) in basedatatypes.py #3441
After upgrading to Plotly 5 (either 5.1.0 or 5.2.2, or 5.3.1, 5.4.0), I am seeing the error (given below) for various plots, at random. The issue goes away if Plotly is downgraded to 4.14.3.
File "plotly/basedatatypes.py", line 3952, in _index_is
raise ValueError("Invalid value")
I have a Dash app that plots several graphs. When the Dash app starts, some plots do not get displayed, and I see the error. This only occurs on the initial startup of the app. When the webpage is refreshed, the error does not re-appear, and all plots get displayed without errors.
If I downgrade to Plotly 4.14.3, the issue goes away entirely.
Reacted by kpms-stephan, benjaminh, 🦦, Matt Cooper and Taylor Denouden
Here is a reproducible (almost reliably) example. Start the script, wait a few sec, access the page at localhost:5000. The failures happen at random on either of the four graphs or several of them at once.
Plotly 5.4.0
Dash 1.21.0 (or 2.0.0 does not matter)
Running the code with debug=False seems to trigger the error more reliably than with debug=True.
Note that this only occurs on the initial startup of the app and the first visit to the page. When the webpage is refreshed, the error does not re-appear, and all plots get displayed without errors.
The error message and the screenshot are given below.
127.0.0.1 - - [29/Oct/2021 19:53:20] "POST /_dash-update-component HTTP/1.1" 500 -
[2021-10-29 19:53:20,832] ERROR in app: Exception on /_dash-update-component [POST]
Traceback (most recent call last):
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/flask/app.py", line 2070, in wsgi_app
response = self.full_dispatch_request()
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/flask/app.py", line 1515, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/flask/app.py", line 1513, in full_dispatch_request
rv = self.dispatch_request()
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/flask/app.py", line 1499, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/dash/dash.py", line 1096, in dispatch
response.set_data(func(*args, outputs_list=outputs_list))
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/dash/dash.py", line 1017, in add_context
output_value = func(*args, **kwargs) # %% callback invoked %%
File "/home/skhan/notebooks/scripts/dash_dev.py", line 37, in update4
return gen_plot()
File "/home/skhan/notebooks/scripts/dash_dev.py", line 8, in gen_plot
return px.bar([1, 2, 3], [4, 5, 4])
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/express/_chart_types.py", line 365, in bar
return make_figure(
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/express/_core.py", line 1931, in make_figure
apply_default_cascade(args)
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/express/_core.py", line 969, in apply_default_cascade
args["pattern_shape_sequence"] = [
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/express/_core.py", line 970, in <listcomp>
bar.marker.pattern.shape for bar in args["template"].data.bar
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/graph_objs/bar/marker/_pattern.py", line 252, in shape
return self["shape"]
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/basedatatypes.py", line 4693, in __getitem__
elif self._props is not None and prop in self._props:
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/basedatatypes.py", line 4388, in _props
return self.parent._get_child_props(self)
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/basedatatypes.py", line 4402, in _get_child_props
if self._props is None:
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/basedatatypes.py", line 4388, in _props
return self.parent._get_child_props(self)
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/basedatatypes.py", line 4402, in _get_child_props
if self._props is None:
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/basedatatypes.py", line 4388, in _props
return self.parent._get_child_props(self)
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/basedatatypes.py", line 4422, in _get_child_props
child_ind = BaseFigure._index_is(children, child)
File "/home/skhan/.virtualenvs/penv-dant-dash/lib/python3.8/site-packages/plotly/basedatatypes.py", line 3952, in _index_is
raise ValueError("Invalid value")
ValueError: Invalid value
Also facing the same issue with a similar setup (Plotly 5.6.0 and Dash 2.3.0) and use case. Exact same behaviour observed : dash app plotting several graphs and a random number of them are not being displayed at startup, with the same error thrown as stated above.
Would be glad to hear some news about it, at least some insights on how to tackle this issue.
Fixed by adding: fig = go.Figure(layout=dict(template='plotly'))
before instantiating the figure.
e.g. fig = go.Figure(layout=dict(template='plotly'))
fig = px.bar(temp_df, ...
Reacted by lutrarutra, Jonathan O'Connell, Angie Semler, Sergiy Khan, Jeremy Grifski, Mark Baker, Gabriel Potvin, Robert Merchant, KoroNiko, Amanda Bezerra and 1 more
I have 11 graphs in 4 tabs in a Dash app, which consistently produced the ValueError(“Invalid value”) error on random graphs. Until now, I was using the workaround with the try.
So, to implement your approach, I removed the try logic, and added figure=go.Figure(layout=dict(template='plotly')) for each dcc.Graph in the layout.
Note that previously, I did not have the value for the figure set in dcc.Graph at all. It was returned by a callback on the startup.
As an experiment, I also tried using figure=go.Figure(), but it did not help.
@plan-9-from-outer-space , Can you please share the code the reproduces this error?
I just the code posted by the original poster, but I didn't get an error.
Original poster is here. The code sample I submitted in 2021 produces the error just fine. I have just tested it again in Dash 2.15.0 and got the same error.
As many other reporters clearly indicated, the nature of this error seems random. Try running the code a few times, and opening a fresh browser tab perphaps for each try?
Below is a link to a self-contained file of code that shows the error. I am using plotly 5.18.0 and dash 2.15.0 (both are the latest versions on pypi.org). I am using python 3.11.7. BTW, I also get an annoying warning from plotly, which gets printed to the terminal whenever I click on one of the dash tabs:
C:...\envs\PY1\Lib\site-packages\plotly\express_core.py:2065: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass (name,) instead of name to silence this warning.
Below is the link to a file that shows the error. Just save locally and run "python dashboard.py".
I forgot to mention -- you will need to comment out line 26, which is the bug fix.
@sergiykhan and @plan-9-from-outer-space thanks for the self-contained apps. But I'm afraid I'm still unable to reproduce this error using either, no matter how much I restart or reload. Looks like it's happening both on Windows and on Linux, any other info those seeing this can give to help us reproduce?
I created a new python environment, installed only python 3.11.7, dash, and pandas, and the same error occurs. I am running Windows 11. Can you try doing that?
That's exactly what I did before, but upon doing it again I did see the error! Seems like there's some sort of a race condition when you fire multiple figure callbacks simultaneously, I couldn't get it to happen with only one graph callback. But also after one or two times showing the error it never happens again, no matter how many times I stop Python and restart it, and/or close and reopen the page, so it's like plotly.py has sorted itself out, maybe generated __pycache__ files or some such, and the problem never recurs.
Thanks for your patience - this is still going to be tricky to figure out but at least I've seen it now!
Two threads can both find the entry empty, both build the list, and the later assignment replaces the earlier one. A thread that already received the first list is now holding children that are no longer in their parent's tuple. When it reads a property on one of them, _get_child_props locates the child via BaseFigure._index_is, which searches by object identity:
Its object isn't there, so ValueError("Invalid value").
This bites servers in particular: the process-global default template (pio.templates) is still cold when the first concurrent requests arrive, and it's plotly's own code (apply_default_cascade) that touches it during an ordinary px.bar(...). There's no seam where a caller could take a lock.
File "plotly/express/_core.py", line 994, in apply_default_cascade
bar.marker.pattern.shape for bar in args["template"].data.bar
File "plotly/graph_objs/bar/marker/_pattern.py", line 252, in shape
return self["shape"]
File "plotly/basedatatypes.py", line 4437, in _props
return self.parent._get_child_props(self)
File "plotly/basedatatypes.py", line 4471, in _get_child_props
child_ind = BaseFigure._index_is(children, child)
File "plotly/basedatatypes.py", line 3965, in _index_is
raise ValueError("Invalid value")
ValueError: Invalid value
Reproduction
Every built-in template is loaded lazily, so each gives one independent cold start to race on. Reproduces in 9–10 out of 10 runs.
importsysimportthreadingimportpandas# noqa: F401 -- import eagerly; narwhals' lazy import has its own raceimportplotlyimportplotly.expressaspximportplotly.ioaspio# Not required to trigger the bug, but shortening the GIL switch interval makes# it reproduce reliably instead of ~1% of the time.sys.setswitchinterval(1e-6)
THREADS=16failures= {}
fortemplate_nameinpio.templates:
pio.templates.default=template_nameerrors= []
barrier=threading.Barrier(THREADS)
defbuild_first_figure():
barrier.wait() # line all threads up on the still-cold templatetry:
px.bar(x=[0], y=[0])
exceptExceptionasexc:
errors.append(exc)
workers= [threading.Thread(target=build_first_figure) for_inrange(THREADS)]
forworkerinworkers:
worker.start()
forworkerinworkers:
worker.join()
iferrors:
failures[template_name] =errorsprint(f"plotly {plotly.__version__} on python {sys.version.split()[0]}")
print(f"{len(failures)}/{len(pio.templates)} templates raced")
forname, errsinfailures.items():
print(f" template {name!r}: {len(errs)}/{THREADS} threads -> "f"{type(errs[0]).__name__}: {errs[0]}")
plotly 5.24.1 on python 3.12.11
3/11 templates raced
template 'ggplot2': 1/16 threads -> ValueError: Invalid value
template 'seaborn': 7/16 threads -> ValueError: Invalid value
template 'plotly_white': 2/16 threads -> ValueError: Invalid value
Affected versions I measured (16 threads, fresh process, rate over 10 runs): 5.24.1, 6.0.1, 6.3.1, 6.6.0, 6.9.0 — all 9–10/10.
Proposed fix
Build first, then publish with setdefault, so the entry is written exactly once and every thread converges on the same object. Threads may still duplicate the work, but no thread can be left holding an orphaned child — which is the invariant _index_is depends on. dict.setdefault is atomic in CPython, and dicts are internally locked under free-threading, so no explicit lock is needed.
--- a/plotly/basedatatypes.py+++ b/plotly/basedatatypes.py
@@
if isinstance(validator, CompoundValidator):
if self._compound_props.get(prop, None) is None:
# Init compound objects
- self._compound_props[prop] = validator.data_class(- _parent=self, plotly_name=prop- )+ child = validator.data_class(_parent=self, plotly_name=prop)
# Update plotly_name value in case the validator applies
# non-standard name (e.g. imagedefaults instead of image)
- self._compound_props[prop]._plotly_name = prop+ child._plotly_name = prop+ # Publish with setdefault, not assignment: two threads can+ # both find the entry empty and both build a child. A plain+ # assignment lets the late one replace an object the other+ # already handed out, orphaning it from this parent so that+ # _get_child_props' identity lookup fails. setdefault makes+ # the first published child win for everyone.+ self._compound_props.setdefault(prop, child)
return validator.present(self._compound_props[prop])
elif isinstance(validator, (CompoundArrayValidator, BaseDataValidator)):
if self._compound_array_props.get(prop, None) is None:
# Init list of compound objects
if self._props is not None:
- self._compound_array_props[prop] = [+ children = [
validator.data_class(_parent=self)
for _ in self._props.get(prop, [])
]
else:
- self._compound_array_props[prop] = []+ children = []+ # See the setdefault note above.+ self._compound_array_props.setdefault(prop, children)
return validator.present(self._compound_array_props[prop])
On 6.9.0, same version, same script, 15 runs each:
reproduced
unpatched
14/15
patched
0/15
Figures still render identically, and template values are unchanged.
Happy to open a PR with this plus a regression test if the approach looks reasonable — or if maintainers would rather have an explicit lock or eager initialisation, that's an easy change.
Possibly separate: a second race in 6.x
While isolating the above I hit a different failure on concurrent first calls, which survives the fix above:
File "plotly/express/_core.py", line 1203, in to_named_series
x = nw.from_native(x, series_only=True, pass_through=True)
File "narwhals/_native.py", line 408, in is_native_pandas
(pd := get_pandas()) is not None and isinstance(obj, (pd.DataFrame, pd.Series))
AttributeError: partially initialized module 'pandas' has no attribute 'DataFrame'
(most likely due to a circular import)
That's narwhals' lazy import pandas racing across threads, unrelated to templates. It's why the repro above imports pandas eagerly. Happy to file separately if it's not already known.
Activity
sergiykhan commentedon Oct 29, 2021
Here is a reproducible (almost reliably) example. Start the script, wait a few sec, access the page at localhost:5000. The failures happen at random on either of the four graphs or several of them at once.
Plotly 5.4.0
Dash 1.21.0 (or 2.0.0 does not matter)
Running the code with
debug=Falseseems to trigger the error more reliably than withdebug=True.Note that this only occurs on the initial startup of the app and the first visit to the page. When the webpage is refreshed, the error does not re-appear, and all plots get displayed without errors.
The error message and the screenshot are given below.
The error:
The screenshot

mrolinek commentedon Dec 13, 2021
I am also hit by this. Is there any progress?
sergiykhan commentedon Dec 13, 2021
I have not heard anything yet, besides a workaround by LeoWY here https://community.plotly.com/t/valueerror-invalid-value-in-basedatatypes-py/55993/6
joseortunomacias commentedon Feb 21, 2022
I found the same problem. Any progress apart from the workaround with the
try?benjaminh commentedon Mar 29, 2022
Also facing the same issue with a similar setup (Plotly 5.6.0 and Dash 2.3.0) and use case. Exact same behaviour observed : dash app plotting several graphs and a random number of them are not being displayed at startup, with the same error thrown as stated above.
Would be glad to hear some news about it, at least some insights on how to tackle this issue.
henriquegrabin commentedon Mar 30, 2022
Same issues here with Plotly 5.6.0 and Dash 2.1.0. For some reason the workaround with the try clause avoids errors.
KnopKirrie commentedon Oct 7, 2022
Fixed by adding:
fig = go.Figure(layout=dict(template='plotly'))before instantiating the figure.
e.g.
fig = go.Figure(layout=dict(template='plotly'))fig = px.bar(temp_df, ...sergiykhan commentedon Apr 7, 2023
Thanks, @KnopKirrie. That helped.
I have 11 graphs in 4 tabs in a Dash app, which consistently produced the
ValueError(“Invalid value”)error on random graphs. Until now, I was using the workaround with thetry.So, to implement your approach, I removed the
trylogic, and addedfigure=go.Figure(layout=dict(template='plotly'))for eachdcc.Graphin the layout.Note that previously, I did not have the value for the
figureset indcc.Graphat all. It was returned by a callback on the startup.As an experiment, I also tried using
figure=go.Figure(), but it did not help.plan-9-from-outer-space commentedon Feb 12, 2024
FYI - This same error is still occurring when using plotly/dash, in 2024. Luckily, the above fix by "KnopKirrie" still works.
In fact, you only have to include this line one time before any of your other plotly or dash code:
go.Figure(layout=dict(template='plotly'))
Coding-with-Adam commentedon Feb 14, 2024
@plan-9-from-outer-space , Can you please share the code the reproduces this error?
I just the code posted by the original poster, but I didn't get an error.
sergiykhan commentedon Feb 14, 2024
Original poster is here. The code sample I submitted in 2021 produces the error just fine. I have just tested it again in Dash 2.15.0 and got the same error.
As many other reporters clearly indicated, the nature of this error seems random. Try running the code a few times, and opening a fresh browser tab perphaps for each try?
plan-9-from-outer-space commentedon Feb 14, 2024
Below is a link to a self-contained file of code that shows the error. I am using plotly 5.18.0 and dash 2.15.0 (both are the latest versions on pypi.org). I am using python 3.11.7. BTW, I also get an annoying warning from plotly, which gets printed to the terminal whenever I click on one of the dash tabs:
C:...\envs\PY1\Lib\site-packages\plotly\express_core.py:2065: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass (name,) instead of name to silence this warning.
Below is the link to a file that shows the error. Just save locally and run "python dashboard.py".
I forgot to mention -- you will need to comment out line 26, which is the bug fix.
dashboard.py
alexcjohnson commentedon Feb 14, 2024
The
FutureWarningis being addressed in #4519@sergiykhan and @plan-9-from-outer-space thanks for the self-contained apps. But I'm afraid I'm still unable to reproduce this error using either, no matter how much I restart or reload. Looks like it's happening both on Windows and on Linux, any other info those seeing this can give to help us reproduce?
plan-9-from-outer-space commentedon Feb 14, 2024
I created a new python environment, installed only python 3.11.7, dash, and pandas, and the same error occurs. I am running Windows 11. Can you try doing that?
alexcjohnson commentedon Feb 15, 2024
That's exactly what I did before, but upon doing it again I did see the error! Seems like there's some sort of a race condition when you fire multiple figure callbacks simultaneously, I couldn't get it to happen with only one graph callback. But also after one or two times showing the error it never happens again, no matter how many times I stop Python and restart it, and/or close and reopen the page, so it's like plotly.py has sorted itself out, maybe generated
__pycache__files or some such, and the problem never recurs.Thanks for your patience - this is still going to be tricky to figure out but at least I've seen it now!
sergiykhan commentedon Feb 15, 2024
@alexcjohnson Not sure if it helps, but here is a bit more info about my test (original post).
I keep the Chrome tab open at http://localhost:5000/, and hit F5 to refresh the page after the app is re-launched.
The algorithm: launch the app, hit F5, check if there is an error, close the app. Repeat.
Right now, I did about 15 attempts. Three attempts produced an error. The number of unrendered plots was between 1 and 3.
I do not recreate the Python virtual environment nor do I clean any files.
hb1915 commentedon Aug 3, 2026
Still reproducible on 6.9.0. I tracked down the mechanism and have a candidate fix — details below in case they're useful.
Cause
BaseLayoutHierarchyType._get_propdoes a check-then-act on a shared dict, with no synchronisation:Two threads can both find the entry empty, both build the list, and the later assignment replaces the earlier one. A thread that already received the first list is now holding children that are no longer in their parent's tuple. When it reads a property on one of them,
_get_child_propslocates the child viaBaseFigure._index_is, which searches by object identity:Its object isn't there, so
ValueError("Invalid value").This bites servers in particular: the process-global default template (
pio.templates) is still cold when the first concurrent requests arrive, and it's plotly's own code (apply_default_cascade) that touches it during an ordinarypx.bar(...). There's no seam where a caller could take a lock.Reproduction
Every built-in template is loaded lazily, so each gives one independent cold start to race on. Reproduces in 9–10 out of 10 runs.
Affected versions I measured (16 threads, fresh process, rate over 10 runs): 5.24.1, 6.0.1, 6.3.1, 6.6.0, 6.9.0 — all 9–10/10.
Proposed fix
Build first, then publish with
setdefault, so the entry is written exactly once and every thread converges on the same object. Threads may still duplicate the work, but no thread can be left holding an orphaned child — which is the invariant_index_isdepends on.dict.setdefaultis atomic in CPython, and dicts are internally locked under free-threading, so no explicit lock is needed.On 6.9.0, same version, same script, 15 runs each:
Figures still render identically, and template values are unchanged.
Happy to open a PR with this plus a regression test if the approach looks reasonable — or if maintainers would rather have an explicit lock or eager initialisation, that's an easy change.
Possibly separate: a second race in 6.x
While isolating the above I hit a different failure on concurrent first calls, which survives the fix above:
That's narwhals' lazy
import pandasracing across threads, unrelated to templates. It's why the repro above imports pandas eagerly. Happy to file separately if it's not already known.robertclaus commentedon Aug 3, 2026
@hb1915 could you open a PR with the change? If it resolves the issue we would love to review it!
hb1915 commentedon Aug 4, 2026
@robertclaus should be there now!
Warm plotly templates once per process to avoid a startup race