Textualize/textual · error · RuntimeError
The `call_from_thread` method must run in a different thread
Error message
The `call_from_thread` method must run in a different thread from the app
What it means
RuntimeError raised by App.call_from_thread when executed on the app's own thread (thread ids match). The API exists specifically to hop from a worker thread onto the event-loop thread; calling it from the loop thread is a misuse.
Source
Thrown at src/textual/app.py:1822
Args:
callback: A callable to run.
*args: Arguments to the callback.
**kwargs: Keyword arguments for the callback.
Raises:
RuntimeError: If the app isn't running or if this method is called from the same
thread where the app is running.
Returns:
The result of the callback.
"""
if self._loop is None:
raise RuntimeError("App is not running")
if self._thread_id == threading.get_ident():
raise RuntimeError(
"The `call_from_thread` method must run in a different thread from the app"
)
callback_with_args = partial(callback, *args, **kwargs)
async def run_callback() -> CallThreadReturnType:
"""Run the callback, set the result or error on the future."""
with self._context():
return await invoke(callback_with_args)
# Post the message to the main loop
future: Future[CallThreadReturnType] = asyncio.run_coroutine_threadsafe(
run_callback(), loop=self._loop
)
result = future.result()
return result
def action_change_theme(self) -> None:View on GitHub (pinned to 06dbeef4bb)
Solutions
- From async context just call the function directly, or await an asyncio helper
- Restrict call_from_thread to @work(thread=True) worker bodies
- In shared helpers, branch on app._thread_id == threading.get_ident()
Example fix
# before
async def on_click(self):
self.app.call_from_thread(self.update_ui) # same thread → error
# after
async def on_click(self):
self.update_ui() Defensive patterns
Strategy: validation
Validate before calling
import threading
if threading.get_ident() != app._thread_id:
app.call_from_thread(cb)
else:
cb() # already on the loop thread Prevention
- Call call_from_thread only inside @work(thread=True) bodies
- From async code, invoke UI updates directly
When it happens
Trigger: Invoking app.call_from_thread(...) inside an async method, on_mount, or any code already running on the app thread.
Common situations: Shared helper functions used both from async handlers and thread workers; copy-pasted thread-updating code into normal event handlers.
Related errors
- App is not running
- There is no active worker in this task or thread.
- Can't animate attribute {attribute!r} on {obj!r}; attribute
- Don't know how to animate {value!r}; Can only animate <int>,
- Can't encode {datum!r}
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/08a1302033853358.
Report an issue: GitHub.