#6847·flet

bug: RawImage.render() ACKs stall in packaged Windows app but work with flet run

Author: emannohCreated Sep 15, 2026Updated Sep 16, 2026
Labelsbug

Duplicate Check

Describe the bug

Flet 0.86.5 RawImage.render() frame acknowledgements stall in a packaged Windows desktop app, while the identical app runs smoothly with flet run.

OpenCV capture remains at ~30–31 FPS in both cases. In the packaged app, await RawImage.render() frequently waits until ack_timeout=1.0 (~1.006 s per frame), while in the development/IDE app acknowledgements arrive normally.

A minimal standalone app containing only VideoCapture, one RawImage, a capture worker, and one async render loop reproduces the issue.

Code sample

Code
python
import asyncio
import time
from pathlib import Path

import cv2
import flet as ft


LOG_FILE = Path.home() / "flet_rawimage_test.log"


def log(message: str):
    with LOG_FILE.open("a", encoding="utf-8") as f:
        f.write(f"{time.perf_counter():.3f}: {message}\n")


async def main(page: ft.Page):
    page.title = "Flet RawImage Camera Test"
    page.window.width = 900
    page.window.height = 700

    raw_image = ft.RawImage(
        width=640,
        height=480,
        fit=ft.BoxFit.CONTAIN,
        ack_timeout=1.0,
    )

    status = ft.Text("Camera stopped")

    running = False
    latest_frame = None
    capture_task_running = False

    async def render_loop():
        nonlocal latest_frame

        while True:
            if not running:
                await asyncio.sleep(0.05)
                continue

            frame = latest_frame

            if frame is None:
                await asyncio.sleep(0.001)
                continue

            # Consume the newest available frame.
            latest_frame = None

            started = time.perf_counter()

            try:
                await raw_image.render(
                    frame,
                    premultiplied=True,
                )
            except TimeoutError:
                elapsed = time.perf_counter() - started
                log(f"RENDER TIMEOUT after {elapsed:.3f} sec")
                continue
            except RuntimeError:
                return

            elapsed = time.perf_counter() - started

            if elapsed >= 0.9:
                log(f"ACK likely timed out: {elapsed:.3f} sec")
            else:
                log(f"ACK OK: {elapsed:.3f} sec")

    def capture_loop():
        nonlocal latest_frame
        nonlocal capture_task_running
        nonlocal running

        capture_task_running = True

        cap = cv2.VideoCapture(0)

        # Change these if your camera doesn't support 640x480.
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

        if not cap.isOpened():
            log("ERROR: camera could not be opened")
            running = False
            capture_task_running = False
            return

        count = 0
        fps_start = time.perf_counter()

        try:
            while running:
                ret, frame = cap.read()

                if not ret:
                    log("ERROR: cap.read() failed")
                    break

                # Draw something so we know OpenCV processing is occurring.
                cv2.line(
                    frame,
                    (0, 240),
                    (640, 240),
                    (0, 255, 0),
                    3,
                )

                cv2.line(
                    frame,
                    (320, 0),
                    (320, 480),
                    (0, 255, 0),
                    3,
                )

                # RawImage expects RGB rather than OpenCV's BGR.
                frame = cv2.cvtColor(
                    frame,
                    cv2.COLOR_BGR2RGB,
                )

                # Drop old frames. The renderer always gets the newest one.
                latest_frame = frame

                count += 1
                now = time.perf_counter()

                if now - fps_start >= 1.0:
                    log(f"Captured FPS: {count}")
                    count = 0
                    fps_start = now

        finally:
            cap.release()
            capture_task_running = False
            log("Capture thread stopped")

    async def toggle_camera(e):
        nonlocal running

        if not running:
            LOG_FILE.write_text("", encoding="utf-8")

            running = True
            status.value = "Camera running"
            toggle_button.content = "Stop camera"
            page.update()

            page.run_thread(capture_loop)

        else:
            running = False
            status.value = "Camera stopped"
            toggle_button.content = "Start camera"
            page.update()

    async def poke_ui(e):
        """
        Intentionally unrelated UI activity. Noticed that this causes
        the RawImage frames to update quicker.
        """
        status.value = f"UI clicked at {time.perf_counter():.1f}"
        page.update()

    toggle_button = ft.Button(
        "Start camera",
        on_click=toggle_camera,
    )

    poke_button = ft.Button(
        "Update unrelated UI",
        on_click=poke_ui,
    )

    page.add(
        ft.Row(
            [
                toggle_button,
                poke_button,
            ]
        ),
        status,
        raw_image,
        ft.Text(f"Log file: {LOG_FILE}"),
    )

    # One persistent render task for the lifetime of the page.
    asyncio.create_task(render_loop())


if __name__ == "__main__":
    ft.run(main)

To reproduce

  1. Run the repro code using flet run. Notice smooth video after clicking "Start camera" button.
  2. Package app with flet build windows. Notice laggy video after clicking "Start camera" button. Also notice quicker video update when repeatedly clicking "Update unrelated UI" button.
  3. Open log file saved to home directory (flet_rawimage_test.py). Notice timeouts ~= 1 s, notice quicker updates when unrelated button clicked.

Expected behavior

Smooth video updates in the packaged app

Screenshots / Videos

Captures

[Upload media here]

Operating System

Windows

Operating system details

Windows 11

Flet version

0.86.5

Regression

I'm not sure / I don't know

Suggestions

No response

Logs

Logs
bash
[Paste your logs here]

Additional details

No response