Skip to content

JSON::ResumableParser raises an error unexpected end of input, expected closing " at line 1 column N #1008

@Watson1978

Description

@Watson1978

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:

  1. 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.
  2. 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.
  3. More data is then fed (<<), appending to / reallocating the buffer String.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions