Skip to content

Give RT/iter the empty input list - #5

Merged
burinc merged 1 commit into
mainfrom
fix/zero-input-iterator
Sep 6, 2026
Merged

burinc merged 1 commit into
mainfrom
fix/zero-input-iterator

Conversation

@yogthos

@yogthos yogthos commented Sep 6, 2026

Copy link
Copy Markdown
Member

Closes #4.

Not the type-hint codegen bridges. latest/run and sample/run both open with

(let [it (.iterator (seq fs))] ...)

and in both, fs can be empty — a zero-input (m/latest f) has no flows at all, and sample splits its varargs so (m/sample f sampler) leaves () as the continuous inputs. An empty seq is nil, and a method call on nil is a NullPointerException.

It only ever ran because jolt answered for the nil. Through 0.8.1 (.iterator nil) handed back an empty iterator and (.toString nil) the empty string; 0.8.2 refuses both, as the JVM always has. So this is ebb's bug, not jolt's — jolt got stricter and stopped covering it. jolt-lang/jolt#867 gates the corrected behavior so it cannot drift back.

clojure.lang.RT/iter is what clojure.core's own walkers use for exactly this, and it takes nil on both hosts (verified against Clojure 1.12.0 on a JVM and against jolt 0.8.2).

The sample half was unreported

Nothing covered a sampler-only sample, which is the single most ordinary shape of the operator:

(m/reduce conj [] (m/sample vector (m/seed [1 2 3])))
;; before: NullPointerException: Cannot invoke "iterator" because the target is null
;; after:  [[1] [2] [3]]

It has a row now, and it fails without the fix.

Verified

  • bin/test under the released 0.8.2 binary: 283 tests, 1199 assertions, 0 failures, 0 errors, three runs.
  • Before the fix, same binary: 2 errors (latest-test/zero-input, missionary-issues-test/latest-supports-zero-inputs-126) — the two the issue reports — plus the new sample row.
  • JOLT_VERSION pin moved 0.8.1 -> 0.8.2 with the fix, per the cutover convention in ci.yml.

The intermittent one-in-ten hang ci.yml documents is untouched and unrelated.

https://claude.ai/code/session_019tGgRzPx3vtr5siPkKjjLE

latest/run and sample/run both open with (.iterator (seq fs)), and in both
`fs` can be empty: a zero-input (m/latest f) has no flows at all, and
(m/sample f sampler) splits its varargs so the continuous inputs are (). An
empty seq is nil, and a method call on nil is a NullPointerException.

It only ever ran because jolt through 0.8.1 answered (.iterator nil) with an
empty iterator instead of refusing it; 0.8.2 refuses it as the JVM always has,
which is what surfaced this as #4. RT/iter is what clojure.core's own walkers
use for this and takes nil on both hosts.

The sample half was unreported and uncovered — a sampler-only sample is the
single most ordinary shape of the operator. It has a row now, and it fails
without the fix.

Pin moved to 0.8.2 with the fix, per the cutover convention in ci.yml.

Closes #4.

Claude-Session: https://claude.ai/code/session_019tGgRzPx3vtr5siPkKjjLE
@burinc
burinc merged commit abf9427 into main Sep 6, 2026
2 checks passed
@burinc
burinc deleted the fix/zero-input-iterator branch September 6, 2026 13:16
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.

m/latest with zero inputs fails under jolt 0.8.2 (NullPointerException)

2 participants