antonmedv/fx · error

Invalid character %q in number

Error message

Invalid character %q in number

What it means

parseMinus consumed a leading '-' but the next character is neither a digit nor (in non-strict mode) n/N (NaN) or i/I (Infinity). A negative number must be followed by a digit, so the parser panics reporting the offending character.

Source

Thrown at internal/jsonx/json.go:267

	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)
	}
	if !p.strict {
		switch p.char {
		case 'n', 'N':
			return p.parseNan(start)
		case 'i', 'I':
			return p.parseInfinity(start)
		}
	}
	panic(fmt.Sprintf("Invalid character %q in number", p.char))
}

func (p *JsonParser) parseNumber(start int) *Node {
	num := &Node{
		Kind:       Number,
		Depth:      p.depth,
		LineNumber: p.lineNumberPlusPlus(),
	}

	// Leading zero
	if p.char == '0' {
		p.next()
	} else {
		for utils.IsDigit(p.char) {
			p.next()
		}
	}

View on GitHub (pinned to 4f31cd3a0c)

Solutions

  1. Replace the bare '-' with a valid negative number (e.g. -1) or null
  2. If the intent was -Infinity or -NaN, disable strict mode so parseMinus accepts n/N and i/I
  3. Validate numeric fields before serialization so empty values become null instead of '-'
  4. Locate the exact position via the %q character in the message and repair that line

Example fix

// before
{"delta": -}
// after
{"delta": -1}  // or null; or use -Infinity with strict=false
Defensive patterns

Strategy: validation

Validate before calling

// Reject bare '-' before parsing
for _, m := range bareMinus.FindAllString(string(b), -1) { // regexp: `(-)([^0-9]|$)`
	_ = m
	return errors.New("minus sign not followed by digit or -Infinity")
}

Try / catch

defer func() {
	if r := recover(); r != nil {
		if msg, ok := r.(string); ok && strings.Contains(msg, "in number") {
			err = fmt.Errorf("malformed negative number: %s", msg)
		}
	}
}()

Prevention

When it happens

Trigger: Parse on inputs like `-,`, `-}`, `- abc`, `"key": -` , or `-NaN`/`-Infinity` while strict mode is enabled (the lenient branch is skipped when p.strict is true).

Common situations: Hand-edited numeric fields left as bare '-', JavaScript payloads with -Infinity parsed in strict mode, template rendering producing `"timeout": -` when a variable was empty, CSV/JSON converters emitting placeholder minus signs.

Understand the failure class

Related errors


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