antonmedv/fx · error

Trailing comma is not allowed in strict mode

Error message

Trailing comma is not allowed in strict mode

What it means

The parser tolerates trailing commas in non-strict mode, but in strict mode (JsonParser created with strict=true) a comma immediately before a closing '}' is rejected. Before panicking, it rewinds the parser position back to the comma (p.set(commaPos)) so the reported location points at the trailing comma. Strict mode follows the JSON RFC, which forbids trailing commas.

Source

Thrown at internal/jsonx/json.go:369

		value := p.parseValue(false)
		value.Key = keyBytes
		value.Parent = object
		p.depth--

		object.Append(value)
		object.Size += 1

		p.skipWhitespace()

		commaPos := p.end
		if p.char == ',' {
			object.End.Comma = true
			p.next()
			p.skipWhitespace()
			if p.char == '}' {
				if p.strict {
					p.set(commaPos)
					panic("Trailing comma is not allowed in strict mode")
				}
				object.End.Comma = false
			} else {
				continue
			}
		}

		if p.char == '}' {
			closeBracket := &Node{
				Kind:       Object,
				Depth:      p.depth,
				LineNumber: p.lineNumberPlusPlus(),
			}
			closeBracket.Value = curlyBracketClose
			closeBracket.Parent = object
			closeBracket.Index = -1
			object.Append(closeBracket)
			p.next()

View on GitHub (pinned to 4f31cd3a0c)

Solutions

  1. Remove the trailing comma before the closing brace: {"a":1,} -> {"a":1}
  2. If trailing commas are acceptable for your use case, parse in non-strict mode instead of strict mode
  3. Normalize the input before parsing (strip ',}' / ',]' sequences)

Example fix

// before (strict parse)
{"a": 1, "b": 2,}

// after
{"a": 1, "b": 2}
Defensive patterns

Strategy: validation

Validate before calling

func stripTrailingCommas(src []byte) []byte {
	// lenient preprocessor: remove ',}' and ',]' outside strings (strict-mode input)
	out := make([]byte, 0, len(src))
	inStr, esc := false, false
	for i := 0; i < len(src); i++ {
		c := src[i]
		if esc { esc = false; out = append(out, c); continue }
		if c == '\\' && inStr { esc = true; out = append(out, c); continue }
		if c == '"' { inStr = !inStr; out = append(out, c); continue }
		if !inStr && c == ',' {
			j := i + 1
			for j < len(src) && (src[j]==' '||src[j]=='\t'||src[j]=='\n'||src[j]=='\r') { j++ }
			if j < len(src) && (src[j] == '}' || src[j] == ']') { continue }
		}
		out = append(out, c)
	}
	return out
}

Try / catch

func parseStrictLenient(p *jsonx.JsonParser, data []byte) (root *jsonx.Node, err error) {
	defer func() {
		if r := recover(); r != nil {
			if strings.Contains(fmt.Sprint(r), "Trailing comma") {
				// fallback: retry after stripping trailing commas
				defer func() { recover() }()
				root = jsonx.NewParser(jsonx.WithStrict(false)).Parse(stripTrailingCommas(data))
				return
			}
			err = fmt.Errorf("json parse failed: %v", r)
		}
	}()
	root = p.Parse(data)
	return
}

Prevention

When it happens

Trigger: Parsing {"a":1,} or {"a":1, } with strict mode enabled (e.g. ParseStrict-style APIs or parser configured with strict: true).

Common situations: JSON copied from JavaScript source or ESLint/Prettier-formatted code where trailing commas are stylistic; build tools emitting JS-flavored JSON; hand-edited config where an entry was deleted leaving a dangling comma.

Related errors


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