Skip to content

[Bug]: React #185 crash opening thread, no floating preview, reload ineffective #15120

Description

@MonkeyMed

Before submitting

Area

apps/web

Steps to reproduce

  1. Open thread "Android App Edge-Case Testing" (d40c4954-a990-4503-951b-9e2e860c4053, model: Codex/GPT)
  2. Renderer crashes immediately with React Add drag-and-drop project reordering to the sidebar #185
  3. No device preview was floated at crash time

Expected behavior

Thread opens and stays usable.

Actual behavior

Renderer crashes with React error #185 (Maximum update depth exceeded). Reload from the crash screen does NOT help – only a hard restart of the app recovers. Reproducible on every open of this thread.

Version or commit

T3 Code (Nightly) 0.0.46-nightly.20261003.2623

Environment

Time: 2026-10-03T08:32:34.119Z
Path: /8327eebb-bf4c-409c-ae15-27306b5aad20/d40c4954-a990-4503-951b-9e2e860c4053 (= /$environmentId/$threadId)

Logs or stack traces

Error: Minified React error #185; visit https://react.dev/errors/185 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
    at fi (t3code://app/assets/dist-C9FzM63a.js:26:27482)
    at li (t3code://app/assets/dist-C9FzM63a.js:26:27007)
    at Is (t3code://app/assets/dist-C9FzM63a.js:26:58530)
    at Fs (t3code://app/assets/dist-C9FzM63a.js:26:58152)
    at t3code://app/assets/_chat-BNSSvl7Y.js:2:135935
    at A (t3code://app/assets/_chat-BNSSvl7Y.js:51:62309)
    at Uc (t3code://app/assets/dist-C9FzM63a.js:26:91665)
    at sl (t3code://app/assets/dist-C9FzM63a.js:26:96136)
    at xl (t3code://app/assets/dist-C9FzM63a.js:26:104930)
    at sl (t3code://app/assets/dist-C9FzM63a.js:26:96123)

Note: _chat offsets differ only slightly from #14959 on .2610 (2:135900 / 51:62314), same ThreadDetailsCard/ChatCanvas frames, but without any floating preview here.

Diagnostics

Thread-ID is absent from local statev2.sqlite/state.sqlite (orchestration_v2_projection_threads, projection_threads, orchestration_events) – crash environment-ID differs from local one, so thread content could not be inspected locally.

Workaround

Reload from crash screen: ineffective. Hard app restart required.

Activity

  1. juliusmarminge commented on Oct 3, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks for the detailed report and for checking #14959 first, @MonkeyMed! Even though you didn't float a preview yourself, this looks like the same crash as #14959. Nightly 0.0.46-nightly.20261003.2623 doesn't have a second trigger for it.

    Same crash site

    Your minified frames match the pair already mapped on .2610. ThreadDetailsCard's layout effect calls reportDetailsCard, and ChatCanvas stores that rect with setDetailsCard. Your offsets (_chat 2:135935 / 51:62309) differ by only a few dozen bytes from that mapping. Those call sites are unchanged on current main (263097a8da).

    Why a floating preview is still involved

    The update loop can only run away while a floating preview is in the canvas state. The details card position is only read inside the preview branch, and a portrait player next to the inline card flips between two positions until React stops with error #185:

    if (preview && container.width > 0 && container.height > 0) {
    frame = resolvePreviewMiniPlayerFrame({ ...preview, container });
    // Dragging stops at a readable chat lane on the left. Resizing can still
    // consume that space when the container requires message overlap.
    const minimumPreviewX =
    preview.lastInteraction === "resize" ? GAP : padding + minChatWidth + GAP;
    // New players start beside the composer, with the workspace card above them.
    if (preview.position === null) frame = { ...frame, y: container.height - frame.height - GAP };
    if (preview.lastInteraction === "resize" && composerHeight > 0) {
    // Lift the preview while chat uses its remaining shrink room, reaching
    // the composer's top before the preview enters the readable chat lane.
    const laneWidth = Math.min(normalWidth, minChatWidth);
    const transitionWidth = Math.max(GAP, normalWidth - laneWidth);
    const lift = Math.min(
    1,
    Math.max(0, (padding + normalWidth + GAP - frame.x) / transitionWidth),
    );
    if (lift > 0) {
    frame = resolvePreviewMiniPlayerFrame({
    width: frame.width,
    position: frame,
    source: preview.source,
    container: {
    ...container,
    height: Math.max(GAP * 2 + 1, container.height - composerHeight * lift),
    },
    });
    }
    }
    const preferredFrame = {
    ...frame,
    ...clampPreviewMiniPlayerPosition(frame, container, frame, undefined, minimumPreviewX),
    };
    // A resize keeps its anchored edge and consumes card height first. A drag
    // clears the full card whenever it can, so moving alone never folds it.
    const cardObstacle = preview.lastInteraction === "resize" ? null : detailsCard;

    const reportDetailsCard = useCallback((next: PreviewMiniPlayerObstacles["detailsCard"]) => {
    setDetailsCard((current) =>
    current?.left === next?.left &&
    current?.right === next?.right &&
    current?.bottom === next?.bottom
    ? current
    : next,
    );
    }, []);

    useLayoutEffect(() => {
    reportDetailsCard?.(
    inlineOpen && cardLeft !== undefined && cardRight !== undefined && cardBottom !== undefined
    ? { left: cardLeft, right: cardRight, bottom: cardBottom }
    : null,
    );
    }, [reportDetailsCard, inlineOpen, cardLeft, cardRight, cardBottom]);

    The player doesn't have to be opened by hand, and it often never shows on screen. The loop is a nested useLayoutEffect, so the crash screen replaces everything before that frame is painted.

    Auto-show floating preview is on by default. It opens a player when a device session shows up after the first snapshot, including when the device row arrives late, or when an agent opens a browser preview. An Android device is the portrait shape that fails to settle, and this thread is about Android testing.

    // A device the agent opens floats over chat like an agent-driven browser,
    // or becomes a panel tab when floating previews are off. Sessions opened by
    // another client arrive the same way; sheet layouts get neither. The first
    // snapshot is a baseline: persisted tabs restore themselves, and existing
    // sessions must not resurrect closed tabs. A session whose device summary
    // has not arrived yet stays out of the baseline so a later snapshot opens it.
    const autoShowFloatingPreview = useClientSettings(selectAutoShowFloatingPreview);
    const previousDeviceSessions = useRef(new Map<string, Set<string>>());
    useEffect(() => {
    if (!activeThreadRef || !deviceStateLoaded) return;
    const threadKey = `${activeThreadRef.environmentId}:${activeThreadRef.threadId}`;
    const sessions = deviceState.sessions.filter(
    (session) => session.threadId === activeThreadRef.threadId,
    );
    const key = (session: (typeof sessions)[number]) => `${session.hostId}:${session.deviceId}`;
    const deviceFor = (session: (typeof sessions)[number]) =>
    deviceState.devices.find(
    (entry) => entry.hostId === session.hostId && entry.id === session.deviceId,
    );
    const previous = previousDeviceSessions.current.get(threadKey);
    previousDeviceSessions.current.set(
    threadKey,
    new Set(sessions.filter((session) => deviceFor(session) !== undefined).map(key)),
    );
    if (!previous || shouldUsePlanSidebarSheet) return;
    for (const session of sessions) {
    if (previous.has(key(session))) continue;
    const device = deviceFor(session);
    if (!device) continue;
    const target = {
    hostId: session.hostId,
    deviceId: session.deviceId,
    platform: device.platform,
    name: device.name,
    };
    if (autoShowFloatingPreview) {
    usePreviewMiniPlayerStore.getState().open(activeThreadRef, { kind: "device", ...target });
    continue;

    The missing row in statev2.sqlite doesn't rule this out either way. The mini player only lives in memory, and this thread's environment id isn't the local one, so its contents were never in that database.

    Status and workarounds

    Open PR #14968 fixes this crash, but it isn't in this nightly yet. Until it lands:

    • Close the inline thread details card, or dock the device or browser preview instead of letting it float.
    • Turn off Auto-show floating preview in the Integrations settings so the app doesn't open one on its own.
    • Reloading from the crash screen returns to the same route, so it crashes again as soon as a player opens. A full restart works because it clears the in-memory player.

    If you can still reproduce this with the floating player confirmed closed on a cold open, that would be a new trigger, so please let us know. Otherwise, your canvas width and whether this thread had a device session or browser tab would be useful on #14959.

  2. juliusmarminge commented on Oct 3, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Closing the leftover duplicate. Canonical #14959 is fixed on main by #14992.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already existsvia-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions