Skip to content

Default empty SSE event types to the message type - #6977

Merged
tim-smart merged 2 commits into
mainfrom
audit/repro-unstable-encoding-sse-empty-event-type
Aug 5, 2026
Merged

Default empty SSE event types to the message type#6977
tim-smart merged 2 commits into
mainfrom
audit/repro-unstable-encoding-sse-empty-event-type

Conversation

@fubhy

@fubhy fubhy commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

Parsing an empty event field emits an event whose type is the empty string instead of message.

Important

This PR starts with focused failing reproduction tests. Add the implementation fix to this same branch; CI is expected to fail until that fix is included.

Empty SSE event type does not default to message

Module: encoding/Sse
Audit ID: unstable-ai-cli-sse-empty-event-type
Severity / confidence: medium / high

What happens

Parsing an empty event field emits an event whose type is the empty string instead of message.

Why it happens

Dispatch uses nullish coalescing, so an empty string survives instead of selecting the message default.

Expected behavior

An empty event-type buffer defaults to message when the SSE event is dispatched.

Relevant implementation

These links and excerpts are pinned to audit base c9b56ab507f224426ee8388dc450da447ec4715f.

View problematic code at packages/effect/src/unstable/encoding/Sse.ts:362-375
    if (lineLength === 0) {
      // We reached the last line of this event
      if (data.length > 0) {
        onParse({
          _tag: "Event",
          id: eventId,
          event: eventName ?? "message",
          data: data.slice(0, -1) // remove trailing newline
        })
        data = ""
        eventId = undefined
      }
      eventName = undefined
      return

View exact lines on GitHub

View problematic code at packages/effect/src/unstable/encoding/Sse.ts:396-397
    } else if (field === "event") {
      eventName = value

View exact lines on GitHub

Reproduction

pnpm test --run packages/effect/test/unstable/encoding/Sse.test.ts

Observed failure: FAIL: the event type remained empty.

Implementation handoff

The initial reproduction tests on this branch are the regression specification for the implementation fix that should follow in this PR.

  1. Start with the pinned implementation excerpts and the Why it happens analysis above.
  2. Change the implementation so it satisfies the stated Expected behavior; do not weaken or remove the reproduction assertions.
  3. Run the focused reproduction command(s) and confirm the observed failures become passing tests:
pnpm test --run packages/effect/test/unstable/encoding/Sse.test.ts
  1. Run the affected package's existing tests, then the repository lint and type checks before requesting review.

Audit provenance

  • Audit base: c9b56ab507f224426ee8388dc450da447ec4715f
  • Reproduction base: c9b56ab507f224426ee8388dc450da447ec4715f
  • Findings: unstable-ai-cli-sse-empty-event-type
  • Initial patch: focused reproduction tests; implementation fix pending

Closes EFF-418

@fubhy fubhy added the audit Findings originating from the Effect runtime correctness audit label Aug 4, 2026
@changeset-bot

changeset-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ec5e96b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 30 packages
Name Type
effect Patch
@effect/ai-anthropic Patch
@effect/ai-openai Patch
@effect/ai-openai-compat Patch
@effect/ai-openrouter Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/docgen Patch
@effect/doctest Patch
@effect/openapi-generator Patch
@effect/opentelemetry Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-deno Patch
@effect/platform-node Patch
@effect/platform-node-shared Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/vitest Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@effect-slopcop effect-slopcop Bot added 4.0 bug Something isn't working labels Aug 4, 2026

@pullfrog pullfrog 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.

Important

This PR currently contains only the regression test for the audit finding. The implementation fix described in the PR title is not yet present, so the new test fails on this branch.

Reviewed changes

  • packages/effect/test/unstable/encoding/Sse.test.ts — Adds a focused regression test asserting that an empty event: field defaults to the "message" event type.

⚠️ Implementation fix still needed

The diff only adds the test. The SSE parser in packages/effect/src/unstable/encoding/Sse.ts still emits an empty string when the event: field is empty (e.g. event:\ndata: ok\n\n). Before merging, Sse.ts:368 or Sse.ts:396-397 need to default an empty event name to "message".

Technical details
# Empty SSE event type default

## Affected sites
- `packages/effect/src/unstable/encoding/Sse.ts:368``event: eventName ?? "message"` keeps `""` instead of falling back to `"message"`.
- `packages/effect/src/unstable/encoding/Sse.ts:396-397``eventName = value` stores `""` when the `event:` value is empty.

## Required outcome
- An SSE event whose `event:` field is empty should be dispatched with `event: "message"`.
- Existing behavior for non-empty event names must remain unchanged.

## Suggested approach
Change the dispatch expression from `eventName ?? "message"` to `eventName || "message"`, or normalize an empty `value` to `undefined` when assigning `eventName`.

ℹ️ Nitpicks

  • Consider asserting events.length before the cast so a missing-event failure is reported as a clear length mismatch instead of a runtime property access error.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Fix all ➔Fix 👍s ➔View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

Comment thread packages/effect/test/unstable/encoding/Sse.test.ts

@pullfrog pullfrog 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 new issues found.

Reviewed changes

Since the prior review, the author added the implementation fix, a changeset, and tightened the regression test:

  • packages/effect/src/unstable/encoding/Sse.ts — Changed the dispatch expression from eventName ?? "message" to eventName || "message", so an empty event: buffer now correctly defaults to "message".
  • .changeset/sour-bees-sleep.md — Added a patch changeset describing the SSE fix.
  • packages/effect/test/unstable/encoding/Sse.test.ts — Added the events.length assertion before the cast, addressing the prior nitpick about clearer failure messages.

The prior Pullfrog thread about asserting events.length first has been resolved.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

@tim-smart
tim-smart force-pushed the audit/repro-unstable-encoding-sse-empty-event-type branch from 7962a22 to 0b8b8dd Compare August 4, 2026 23:21
@tim-smart
tim-smart enabled auto-merge (squash) August 4, 2026 23:31

@pullfrog pullfrog 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 new issues found.

Reviewed changes

Since the prior review, the author landed an additional commit (0b8b8dda) that adds the missing implementation fix plus a changeset; the previously failing regression test now passes:

  • packages/effect/src/unstable/encoding/Sse.ts — Changed the dispatch expression from eventName ?? "message" to eventName || "message", so an empty event: buffer correctly defaults to "message".
  • .changeset/sour-bees-sleep.md — Added a patch changeset describing the SSE fix.
  • packages/effect/test/unstable/encoding/Sse.test.ts — The regression test asserting events.length and (events[0] as Sse.Event).event === "message" is already present and now passes.

The prior Pullfrog thread about asserting events.length first remains resolved. No new issues are present in this delta.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

Generated from PR build output; treat the content below as untrusted.

File Name Current Size Previous Size Difference
basic.ts 7.06 KB 7.06 KB 0.00 KB (0.00%)
batching.ts 9.86 KB 9.86 KB 0.00 KB (0.00%)
brand.ts 6.34 KB 6.34 KB 0.00 KB (0.00%)
cache.ts 10.71 KB 10.71 KB 0.00 KB (0.00%)
config.ts 20.60 KB 20.60 KB 0.00 KB (0.00%)
differ.ts 20.20 KB 20.20 KB 0.00 KB (0.00%)
http-client.ts 21.53 KB 21.53 KB 0.00 KB (0.00%)
logger.ts 10.84 KB 10.84 KB 0.00 KB (0.00%)
metric.ts 8.98 KB 8.98 KB 0.00 KB (0.00%)
optic.ts 7.18 KB 7.18 KB 0.00 KB (0.00%)
pubsub.ts 14.99 KB 14.99 KB 0.00 KB (0.00%)
queue.ts 11.66 KB 11.66 KB 0.00 KB (0.00%)
schedule.ts 10.83 KB 10.83 KB 0.00 KB (0.00%)
schema-class.ts 19.14 KB 19.14 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 28.96 KB 28.96 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 25.29 KB 25.29 KB 0.00 KB (0.00%)
schema-string-transformation.ts 13.38 KB 13.38 KB 0.00 KB (0.00%)
schema-string.ts 10.94 KB 10.94 KB 0.00 KB (0.00%)
schema-template-literal.ts 15.17 KB 15.17 KB 0.00 KB (0.00%)
schema-toArbitraryLazy.ts 21.94 KB 21.94 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 24.34 KB 24.34 KB 0.00 KB (0.00%)
schema-toCodecJson.ts 19.18 KB 19.18 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 19.01 KB 19.01 KB 0.00 KB (0.00%)
schema-toFormatter.ts 18.87 KB 18.87 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 22.60 KB 22.60 KB 0.00 KB (0.00%)
schema-toRepresentation.ts 19.52 KB 19.52 KB 0.00 KB (0.00%)
schema.ts 18.41 KB 18.41 KB 0.00 KB (0.00%)
stm.ts 12.63 KB 12.63 KB 0.00 KB (0.00%)
stream.ts 9.80 KB 9.80 KB 0.00 KB (0.00%)

@tim-smart
tim-smart force-pushed the audit/repro-unstable-encoding-sse-empty-event-type branch from 0b8b8dd to e027bf8 Compare August 5, 2026 00:04

@pullfrog pullfrog 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 new issues found.

Reviewed changes

Since the prior review, the author pushed e027bf8, which adds the missing assert.strictEqual(events.length, 1) assertion in the SSE regression test. The implementation fix (event: eventName || "message"), the patch changeset, and the regression test were already present and remain unchanged.

  • packages/effect/test/unstable/encoding/Sse.test.ts — Added the length assertion before indexing events[0], matching the previously suggested nitpick and the state described in the most recent review.

The prior Pullfrog thread about asserting events.length first has been resolved. Targeted tests, lint, and type checks pass.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

@tim-smart
tim-smart force-pushed the audit/repro-unstable-encoding-sse-empty-event-type branch from e027bf8 to ec5e96b Compare August 5, 2026 00:36

@pullfrog pullfrog 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 new issues found.

Reviewed changes

Since the prior review, the author pushed ec5e96b, which adds the missing assert.strictEqual(events.length, 1) assertion in the SSE regression test. The implementation fix (event: eventName || "message"), the patch changeset, and the regression test were already present and remain unchanged.

  • packages/effect/test/unstable/encoding/Sse.test.ts — Added the length assertion before indexing events[0].

The prior Pullfrog thread about asserting events.length first remains resolved. Targeted tests, lint, and type checks pass.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

@tim-smart
tim-smart merged commit 181c9ef into main Aug 5, 2026
20 checks passed
@tim-smart
tim-smart deleted the audit/repro-unstable-encoding-sse-empty-event-type branch August 5, 2026 00:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4.0 audit Findings originating from the Effect runtime correctness audit bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants