Skip to content

fix(summarizer): raise on stream failure instead of swallowing it as an empty summary#324

Merged
ruzin merged 1 commit into
ruzin:mainfrom
Optic00:fix/summarizer-swallowed-stream-failure
Jul 8, 2026
Merged

fix(summarizer): raise on stream failure instead of swallowing it as an empty summary#324
ruzin merged 1 commit into
ruzin:mainfrom
Optic00:fix/summarizer-swallowed-stream-failure

Conversation

@Optic00

@Optic00 Optic00 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Problem

When a summary stream fails (Ollama returning 404 "model not found", a cloud API error, or an adapter error record), the failure was swallowed and reported as success: the user got an empty note ("No summary available for this meeting") with no error surfaced anywhere. Reproduced end-to-end against a real meeting with a broken Ollama: the backend logged ERROR - Ollama streaming failed: ... 404 but still printed STREAM_COMPLETE + Summary reprocessed successfully and exited 0.

Root cause: the streaming generators in src/summarizer.py logged provider errors and then ended the generator silently (logger.error(...); return). Everything downstream was already correct - all five consumer sites in simple_recorder.py catch generator exceptions and emit STREAM_ERROR + exit 1, and app/main.js maps that to failure events. The generators just never raised into that path. This is also the root cause of #301 (cloud streaming failures swallowed).

Fix

src/summarizer.py only - no consumer changes needed:

  • _stream_completion: all four provider paths (Anthropic, Bedrock, OpenAI-compatible, Ollama) now log and re-raise the original exception, so the real message (e.g. model 'x' not found (404)) reaches the UI via STREAM_ERROR.
  • _adapter_stream: an NDJSON error record, an HTTPError, and transport errors now raise after logging. Its second consumer (query_transcript_streaming, the chat path) already catches provider errors and yields a visible [Error: ...] chunk, so chat via the adapter now shows the error instead of an empty answer.
  • summarize_transcript_streaming: defense-in-depth empty-stream guard - a stream that completes without raising but yields no non-whitespace content raises ValueError instead of saving an empty summary. Mirrors the existing empty-reduce guard in _map_reduce_streaming.

A failed regenerate can no longer clobber an existing good summary: the consumers exit before the write.

Tests

  • Unit (tests/test_summarizer_stream_errors.py, 11 tests, written first and failing before the fix): error propagation for the Ollama, Anthropic, Bedrock, OpenAI-compatible and adapter paths (error record / HTTPError / transport), the empty-stream guard (plain + template path), and a success-passthrough regression guard.
  • e2e (model-free T2, e2e/specs/summarize-failure.t2.spec.ts): drives a real reprocess against a mock Ollama answering /api/chat with the real 404 shape (new opt-in chatError option in mock-ollama.js, default off - existing specs unaffected) and asserts the operation reports success:false and the pre-existing summary on disk stays byte-for-byte unchanged.
  • Full backend suite green, summarize-contract e2e re-run green (mock change is non-breaking), backend bundle rebuilt before the e2e run so the spec proves the fix end-to-end.

Fixes #301


Summary by cubic

Surface real errors from summary streaming and stop saving empty notes. Failures (e.g., Ollama 404, cloud API, adapter errors) now trigger STREAM_ERROR and never overwrite a good summary.

  • Bug Fixes

Written for commit 49e73b4. Summary will update on new commits.

Review in cubic

…an empty summary

A failed summary stream (Ollama 404, cloud API error, adapter error record)
was logged and then swallowed (bare return), so consumers saw an
empty-but-successful stream and wrote an empty note + STREAM_COMPLETE +
exit 0 with no error surfaced anywhere. The whole downstream error path
(STREAM_ERROR + exit 1 in simple_recorder, failure mapping in app/main.js)
already existed - the generators just never raised into it.

- _stream_completion: all four provider paths (anthropic/bedrock/openai/
  ollama) now log + raise the original exception
- _adapter_stream: error NDJSON record, HTTPError, and transport errors
  now raise (query_transcript_streaming catches and shows them inline)
- summarize_transcript_streaming: empty-stream guard - a stream that
  completes without raising but yields no non-whitespace content raises
  ValueError instead of saving an empty summary (mirrors the existing
  map-reduce empty-reduce guard)
- tests: unit coverage for all provider paths + empty-stream guard;
  model-free t2 e2e (summarize-failure) drives reprocess against a mock
  Ollama 404 and asserts honest failure + the existing summary untouched

Fixes ruzin#301
@Optic00 Optic00 requested a review from ruzin as a code owner July 7, 2026 23:14

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

Re-trigger cubic

@ruzin ruzin merged commit 88a73f2 into ruzin:main Jul 8, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cloud (Bedrock/OpenAI/Anthropic) streaming failures are swallowed, producing an empty "successful" summary

2 participants