cocoindex-io/cocoindex · error · TypeError
watch() is not supported when preview=True
Error message
watch() is not supported when preview=True
What it means
App.watch() streams live progress updates as incremental processing happens. When the App was configured with preview=True it runs a one-shot preview and produces no continuous change stream, so watch() is meaningless and raises TypeError.
Solutions
- Set preview=False in the App config, then call watch()
- For preview runs, await app.update() and read the final snapshot instead of watching
- Create a separate non-preview App instance for watching
Example fix
// before app = coco.App(coco.AppConfig(name="demo", preview=True), main) async for snap in app.watch(): ... // after app = coco.App(coco.AppConfig(name="demo"), main) async for snap in app.watch(): ...
Defensive patterns
Strategy: validation
Validate before calling
if not app._preview:
async for snap in app.watch():
...
else:
await app.update() # preview: one-shot only Type guard
def supports_watch(app) -> bool:
return not getattr(app, "_preview", False) Try / catch
try:
async for snap in app.watch():
...
except TypeError as e:
if "preview=True" in str(e):
await app.update() # fall back to one-shot preview result Prevention
- Only call watch() on non-preview Apps
- If preview and watch are both needed, build two App instances with different configs
When it happens
Trigger: Calling app.watch() (directly or via _drive_to_ready) on an App constructed with coco.AppConfig(..., preview=True) or preview=True passed to the App.
Common situations: Reusing a preview-mode App for a long-running watcher; toggling preview on for debugging and forgetting it before adding watch(); copying example watch() code into a preview app.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot use sync 'with coco.runtime()' from within an async…
- coco.use_state() cannot be called inside a `with…
- LiveComponent classes cannot be used with use_mount(). Use…
- mount_each() requires a ComponentSubpath when the function…
- mount() requires a ComponentSubpath when the function has…
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/f026b89f18b46b4e.
Report an issue: GitHub.
Appendix: source
Thrown at python/cocoindex/_internal/app.py:105
if self._core_handle is None:
return None
return self._snapshot_from_handle(self._core_handle).stats
async def watch(self) -> AsyncIterator[UpdateSnapshot[R]]:
"""Async iterator that yields progress snapshots.
Yields UpdateSnapshot with status:
- RUNNING while the update is in progress (not yet ready)
- READY when the root component is ready (initial processing caught up)
In live mode, after the initial READY, continues yielding RUNNING snapshots
as stats update from incremental processing. When terminated, yields a final
READY snapshot with the result set.
On error, raises the exception directly from the iterator.
"""
if self._preview:
raise TypeError("watch() is not supported when preview=True")
handle = await self._ensure_started()
last_version = 0
while True:
version = await handle.changed()
# Check termination before dedup — notify_terminated() sends
# TERMINATED_VERSION on the watch channel without updating the
# stats version, so the dedup check would skip it.
if version >= _TERMINATED_VERSION:
snap = self._snapshot_from_handle(handle)
pyvalue: Any = await handle.result()
result: R = pyvalue.get(fn_ret_deserializer(self._main_fn))
if snap.stats is not None:
yield UpdateSnapshot(
stats=snap.stats, status=UpdateStatus.READY, result=result
)
return
View on GitHub (pinned to e84aa99b32)