First of all, thank you so much for your incredible work on the json gem and the recent addition of JSON::ResumableParser.
It is an amazing addition to the library.
when a string value is fed across a << boundary AND parse is called once while the parser is suspended in the middle of that string.
The value is then parsed correctly, but a later parse (which correctly returns false at end-of-stream) leaves a JSON::ParserError that surfaces at a later checkpoint.
The reported column points back to the opening quote of the string that straddled the boundary, which suggests stale frame state rather than a real parse condition.
Environment
- json: commit hash = 02346d8
- ruby: ruby 4.0.5 (2026-05-20 revision 64336ffd0e) +PRISM [x86_64-linux]
Reproduction
The trigger is a parse call between the two feeds, while suspended inside
the string:
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'json', git: 'https://github.com/ruby/json.git'
end
parser = JSON::ResumableParser.new({})
parser << '{"message": "hello '
p parser.parse # => false (needs more input; records mid-string frame state)
parser << 'world"}' # append -> buffer is reallocated, invalidating that state
p parser.parse # => true
p parser.value # => {"message"=>"hello world"} (correct)
p parser.eos? # => true (buffer fully drained)
p parser.rest # => "" (no leftover bytes)
p parser.parse # => false ... but a deferred JSON::ParserError is raised
Result: all of the above print as commented, then:
... in 'JSON::ResumableParser#parse': unexpected end of input, expected closing " at line 1 column 13 (JSON::ParserError)
and the backtrace points at the intermediate parse call (the one that returned false).
The same path is hit by the natural streaming loop, where it raises during the loop.
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'json', git: 'https://github.com/ruby/json.git'
end
parser = JSON::ResumableParser.new({})
['{"message": "hello ', 'world"}'].each do |chunk|
parser << chunk
while parser.parse
p parser.value
end
end
Expected
The trailing parse should simply return false
Required preconditions
All three are needed; remove any one and it parses cleanly:
- The
<< boundary lands inside a string that is a value within a container (object/array).
A split between documents, or outside any string, is fine.
parse is called while the parser is suspended inside that string (it returns false).
If both feeds happen before the first parse, there is no error.
- More data is then fed (
<<), appending to / reallocating the buffer String.
First of all, thank you so much for your incredible work on the json gem and the recent addition of
JSON::ResumableParser.It is an amazing addition to the library.
when a string value is fed across a
<<boundary ANDparseis called once while the parser is suspended in the middle of that string.The value is then parsed correctly, but a later
parse(which correctly returnsfalseat end-of-stream) leaves aJSON::ParserErrorthat surfaces at a later checkpoint.The reported column points back to the opening quote of the string that straddled the boundary, which suggests stale frame state rather than a real parse condition.
Environment
Reproduction
The trigger is a
parsecall between the two feeds, while suspended insidethe string:
Result: all of the above print as commented, then:
and the backtrace points at the intermediate
parsecall (the one that returnedfalse).The same path is hit by the natural streaming loop, where it raises during the loop.
Expected
The trailing
parseshould simply returnfalseRequired preconditions
All three are needed; remove any one and it parses cleanly:
<<boundary lands inside a string that is a value within a container (object/array).A split between documents, or outside any string, is fine.
parseis called while the parser is suspended inside that string (it returnsfalse).If both feeds happen before the first
parse, there is no error.<<), appending to / reallocating the buffer String.