Skip to content

subscribeRunEvents has an unsubscribe-function signature but unconditionally throws #30

Description

@bornajerk
  subscribeRunEvents(
    _runId: string,
    _onEvent: (event: unknown) => void
  ): () => void {
    // Placeholder for SSE subscription
    // Future implementation will use EventSource for /api/runs/:id/stream
    console.warn("subscribeRunEvents not yet implemented in realClient")

    throw createApiError(
      ApiErrorCode.NOT_IMPLEMENTED,
      "Real-time streaming not yet implemented. Use polling with refetchInterval instead.",
      generateRequestId("real")
    )
  }

(frontend/src/lib/api/realClient.ts:311-325)

The declared return type () => void promises a teardown function. TypeScript accepts the body because a function that always throws is assignable to anything — so the type system offers no warning here at all.

Trigger: the first developer to wire up live run events writes the natural thing:

useEffect(() => api.subscribeRunEvents(runId, onEvent), [runId])

Observed: the effect throws during commit. React unwinds to the nearest boundary — the app-wide ErrorBoundary at App.tsx:49 — and the whole console is replaced by the error card. Not a console warning, not a degraded panel: a full-screen failure, from opting into a method the interface appears to offer.
Expected: either the method does not exist, or calling it is safe.

Two clean options:

// (a) honest no-op — callers keep working, nothing explodes
subscribeRunEvents(): () => void {
  console.warn("SSE not implemented; falling back to polling")
  return () => {}
}
// (b) remove it, and let the absence be a compile error at the call site

I would take (b). This method is not on the ApiClient interface in frontend/src/lib/api/client.ts:15-55, so nothing typed against ApiClient can even see it — it is reachable only by someone who imports RealApiClient concretely and goes looking. That makes it a trap with no upside. Worth noting the codebase already made the right call elsewhere: every panel polls on a 2s interval instead (e.g. IdeaGenerationPanel.tsx:267), which is exactly what the error message recommends.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions