antonmedv/fx · error

Unexpected end of input in string

Error message

Unexpected end of input in string

What it means

scanString reached end-of-input (p.char == 0 sentinel set on EOF) while still scanning a string literal — the closing double quote was never found. The library panics because a string cannot be terminated.

Source

Thrown at internal/jsonx/json.go:239

							panic(fmt.Sprintf("Invalid Unicode escape sequence '\\u%s%c'", s, p.char))
						}
						s += string(p.char)
					}
					_, err := strconv.ParseInt(s, 16, 32)
					if err != nil {
						panic(fmt.Sprintf("Invalid Unicode escape sequence '\\u%s'", s))
					}
				case '"', '\\', '/', 'b', 'f', 'n', 'r', 't':
				default:
					panic(fmt.Sprintf("Invalid escape sequence '\\%c'", p.char))
				}
			}
		} else if p.char == '\\' {
			escaped = true
		} else if p.char == '"' {
			break
		} else if p.char == 0 {
			panic("Unexpected end of input in string")
		} else if rune(p.char) > unicode.MaxRune {
			panic(fmt.Sprintf("Invalid character code point %d in string", p.char))
		}
		p.next()
	}

	str := string(p.data[start:p.end])
	p.next()

	return str
}

func (p *JsonParser) parseMinus() *Node {
	start := p.end - 1
	p.next()
	switch p.char {
	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
		return p.parseNumber(start)

View on GitHub (pinned to 4f31cd3a0c)

Solutions

  1. Check the input source for truncation and re-fetch/re-download the complete document
  2. Add the missing closing quote at the reported line
  3. Verify file sizes / Content-Length vs received bytes when reading from network or disk
  4. Recover in the caller and report a user-friendly 'unterminated string at line N' message

Example fix

// before
{"name": "unclosed
// after
{"name": "unclosed"}
Defensive patterns

Strategy: try-catch

Validate before calling

// Cheap sanity check: balanced double quotes outside escapes
func quotesBalanced(b []byte) bool {
	inStr, esc := false, false
	for _, c := range b {
		if esc { esc = false; continue }
		switch c {
		case '\\':
			if inStr { esc = true }
		case '"':
			inStr = !inStr
		}
	}
	return !inStr
}

Try / catch

func parse(b []byte) (n *jsonx.Node, err error) {
	defer func() {
		if r := recover(); r != nil {
			if msg, ok := r.(string); ok && strings.Contains(msg, "Unexpected end of input") {
				err = errors.New("truncated input: unterminated string")
			}
		}
	}()
	return jsonx.Parse(b, true), nil
}

Prevention

When it happens

Trigger: Parse on input where an opening '"' is never closed, e.g. `{"key": "value}` or a file truncated mid-string; also when the input ends immediately after an opening quote.

Common situations: Truncated network responses or downloads, log lines cut mid-record, editors saving partial files, streaming reads where the producer crashed, accidental deletion of the closing quote during hand edits.

Understand the failure class

Related errors


AI-assisted analysis of antonmedv/fx@4f31cd3a0c (2026-09-02). Data as JSON: /api/errors/222ae7768a6b7a0c. Report an issue: GitHub.