Skip to content

Fix SQL resolvers executing empty batches - #7120

Merged
tim-smart merged 4 commits into
mainfrom
audit/repro-b206fa5d76-sql-resolver-empty-encoded-batch
Aug 8, 2026
Merged

Fix SQL resolvers executing empty batches#7120
tim-smart merged 4 commits into
mainfrom
audit/repro-b206fa5d76-sql-resolver-empty-encoded-batch

Conversation

@fubhy

@fubhy fubhy commented Aug 7, 2026

Copy link
Copy Markdown
Member

Summary

SQL resolver constructors invoked options.execute(inputs) after request encoding even when every request failed encoding and inputs was empty. This violated the public Arr.NonEmptyArray callback contract.

This PR now guards the ordered, grouped, findById, and void resolvers against empty encoded batches and adds focused regression coverage for every path.

SQL resolvers invoke NonEmpty callbacks with an empty batch

Module: packages/effect/src/unstable/sql/SqlResolver.ts
Audit ID: relsem-sql-empty-encoded-batch
Severity / confidence: medium / high

What happens

Each resolver partitions requests by whether encoding succeeds. Previously, execute was invoked unconditionally after partitioning, so an all-invalid batch reached a callback typed to accept only Arr.NonEmptyArray.

Expected behavior

The resolver execute callbacks receive only non-empty encoded input batches. Per-request encoding failures complete those requests with SchemaError and do not trigger an impossible empty execution.

Implementation

Each resolver now narrows the encoded inputs with Arr.isArrayNonEmpty before invoking execute. The existing SqlResolver.test.ts covers all-invalid batches for ordered, grouped, findById, and void.

Validation

pnpm test --run packages/effect/test/unstable/sql/SqlResolver.test.ts
pnpm test --run --project effect
pnpm lint
pnpm check

Audit provenance

  • Audit base: b206fa5d7655c1634c9993410a9203f6616a5ca2
  • Reproduction base: b206fa5d7655c1634c9993410a9203f6616a5ca2
  • Finding: relsem-sql-empty-encoded-batch

Closes EFF-555

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

changeset-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d55e535

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 7, 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 adds a correct reproduction test, but the implementation fix it claims to make is not present in the current commit. CI is expected to fail until the fix lands.

Reviewed changes

Reviewed the single added regression test in packages/effect/test/unstable/sql/SqlResolver.test.ts and the unchanged implementation in packages/effect/src/unstable/sql/SqlResolver.ts that it exercises.

  • Added a focused reproduction test showing SqlResolver.ordered calls execute with an empty batch when every request fails encoding.

The test fails as expected against the current source (executions is 1, expected 0), confirming the bug. Before this can merge, packages/effect/src/unstable/sql/SqlResolver.ts needs to guard every options.execute(inputs) call so it is only invoked when inputs is non-empty. The PR body calls out both ordered and findById; the current implementation also calls execute unconditionally in grouped and void, so those should be covered for consistency.

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/sql/SqlResolver.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

Reviewed the new commit 6246060 against the prior Pullfrog review at abf4f5e.

  • Added Arr.isArrayNonEmpty guards before options.execute(inputs) in ordered, grouped, findById, and void_ so empty encoded batches never reach a callback typed as Arr.NonEmptyArray.
  • Removed the as any casts on inputs now that the guard narrows the type.
  • Added focused regression tests for grouped, findById, ordered, and void that assert no execute call and a failed exit when every request fails encoding.
  • Added a changeset describing the effect patch.

The prior Pullfrog thread requesting an analogous findById regression test is addressed and resolved.

Validation run:

  • pnpm test --run packages/effect/test/unstable/sql/SqlResolver.test.ts passes (6 tests).
  • pnpm --filter effect check passes.
  • pnpm lint-fix on the changed files produces no changes.

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 7, 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 6.92 KB 6.92 KB 0.00 KB (0.00%)
batching.ts 9.72 KB 9.72 KB 0.00 KB (0.00%)
brand.ts 6.60 KB 6.60 KB 0.00 KB (0.00%)
cache.ts 10.59 KB 10.59 KB 0.00 KB (0.00%)
config.ts 20.88 KB 20.88 KB 0.00 KB (0.00%)
differ.ts 19.74 KB 19.74 KB 0.00 KB (0.00%)
http-client.ts 21.52 KB 21.52 KB 0.00 KB (0.00%)
logger.ts 10.81 KB 10.81 KB 0.00 KB (0.00%)
metric.ts 8.86 KB 8.86 KB 0.00 KB (0.00%)
optic.ts 6.68 KB 6.68 KB 0.00 KB (0.00%)
pubsub.ts 14.86 KB 14.86 KB 0.00 KB (0.00%)
queue.ts 11.54 KB 11.54 KB 0.00 KB (0.00%)
schedule.ts 10.71 KB 10.71 KB 0.00 KB (0.00%)
schema-class.ts 19.45 KB 19.45 KB 0.00 KB (0.00%)
schema-fromJsonSchemaDocument.ts 29.32 KB 29.32 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 25.59 KB 25.59 KB 0.00 KB (0.00%)
schema-string-transformation.ts 13.52 KB 13.52 KB 0.00 KB (0.00%)
schema-string.ts 11.05 KB 11.05 KB 0.00 KB (0.00%)
schema-template-literal.ts 15.35 KB 15.35 KB 0.00 KB (0.00%)
schema-toArbitraryLazy.ts 21.48 KB 21.48 KB 0.00 KB (0.00%)
schema-toCodeDocument.ts 23.96 KB 23.96 KB 0.00 KB (0.00%)
schema-toCodecJson.ts 18.70 KB 18.70 KB 0.00 KB (0.00%)
schema-toEquivalence.ts 18.53 KB 18.53 KB 0.00 KB (0.00%)
schema-toFormatter.ts 18.39 KB 18.39 KB 0.00 KB (0.00%)
schema-toJsonSchemaDocument.ts 22.16 KB 22.16 KB 0.00 KB (0.00%)
schema-toRepresentation.ts 19.05 KB 19.05 KB 0.00 KB (0.00%)
schema.ts 18.69 KB 18.69 KB 0.00 KB (0.00%)
stm.ts 12.59 KB 12.59 KB 0.00 KB (0.00%)
stream.ts 9.67 KB 9.67 KB 0.00 KB (0.00%)

@tim-smart tim-smart changed the title Fix sQL ordered resolvers invoke NonEmpty callbacks with an empty batch Fix SQL resolvers executing empty batches Aug 7, 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.

✅ No new issues found.

Reviewed changes

Reviewed the new commit 9520a88 against the prior Pullfrog review at 6246060.

  • Refactored partitionRequestsById in packages/effect/src/unstable/sql/SqlResolver.ts to build the ID deduplication map before encoding any request, then encode only the unique IDs in a second pass. This prevents duplicate requests for an invalid ID from being left uncompleted when encoding fails and the resolver returns early on an empty batch.
  • Updated the duplicate-merging completeUnsafe closure to cascade completion through the deduplication chain.
  • Added a focused regression test in packages/effect/test/unstable/sql/SqlResolver.test.ts verifying that two concurrent findById requests for the same invalid ID both complete with SchemaError.
  • Tightened existing empty-batch regression assertions from Exit.isFailure to error._tag === "SchemaError" via Effect.flip.

Validation run:

  • pnpm test --run packages/effect/test/unstable/sql/SqlResolver.test.ts passes (7 tests).
  • pnpm --filter effect check passes.
  • pnpm lint-fix on the changed files produces no changes.

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-b206fa5d76-sql-resolver-empty-encoded-batch branch from 9520a88 to 5e7137f Compare August 8, 2026 01:00

@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

Reviewed the new commit 5e7137f ("Simplify SQL resolver request encoding") against the prior Pullfrog review at 9520a88. The PR branch was rebased onto newer main (b9875ea), so the earlier commits now carry different SHAs but the same content as already reviewed.

  • Refactored partitionRequestsById in packages/effect/src/unstable/sql/SqlResolver.ts to encode each deduplicated entry with a per-iteration matchCauseEager closure and yield*, replacing the previous shared-mutable-entry + handle closure + yield (...) pattern. This is behavior-preserving and removes the mutable-capture hazard that originally caused duplicate invalid requests to be left uncompleted.

Validation run:

  • pnpm test --run packages/effect/test/unstable/sql/SqlResolver.test.ts passes (7 tests).
  • pnpm --filter effect check passes.

No new issues introduced by this refactor; all four resolver Arr.isArrayNonEmpty guards remain in place.

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 DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@tim-smart
tim-smart enabled auto-merge (squash) August 8, 2026 01:12
@tim-smart
tim-smart merged commit 615d1d5 into main Aug 8, 2026
19 checks passed
@tim-smart
tim-smart deleted the audit/repro-b206fa5d76-sql-resolver-empty-encoded-batch branch August 8, 2026 01:14
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