antonmedv/fx · error
unsupported node kind %d
Error message
unsupported node kind %d
What it means
ToValue converts an internal JSON Node into a goja (JavaScript) value. It switches on the node's Kind; when the kind is not one of the recognized kinds (Null, Bool, Number, String, Object, Array, Undefined), the node data is corrupted or came from a parser that produced an unknown kind, so it panics with 'unsupported node kind %d'. This is an internal invariant violation, not a user-input error.
Source
Thrown at internal/jsonx/to_value.go:113
}
}
return vm.NewArray(arr...)
case NaN:
return vm.ToValue(math.NaN())
case Infinity:
if n.Value[0] == '-' {
return vm.ToValue(math.Inf(-1))
}
return vm.ToValue(math.Inf(1))
case Undefined:
return goja.Undefined()
}
panic(fmt.Sprintf("unsupported node kind %d", n.Kind))
}
// maxSafeInt is 2^53 - 1, the largest integer JS can represent exactly.
const maxSafeInt = 1<<53 - 1
// minSafeInt is -(2^53 - 1).
const minSafeInt = -maxSafeInt
// ParseNumber parses a number from a string as int64 or *big.Int.
func ParseNumber(s string) (interface{}, bool) {
bi := new(big.Int)
if _, ok := bi.SetString(s, 10); !ok {
return nil, false
}
// Quickly reject values whose bit-length exceeds 54 (i.e. >= 2^53).
// big.Int.BitLen returns the length of the absolute value in bits.
if bi.BitLen() <= 53 {View on GitHub (pinned to 4f31cd3a0c)
Solutions
- Inspect the panic message's kind number and add a matching case to the switch in ToValue (internal/jsonx/to_value.go)
- Ensure every Node construction site assigns a valid Kind constant from the jsonx package
- Update the library version so the node producer and ToValue switch are from the same code version
Example fix
// before
case Undefined:
return goja.Undefined()
}
panic(fmt.Sprintf("unsupported node kind %d", n.Kind))
// after
case Undefined:
return goja.Undefined()
case MyNewKind:
return vm.ToValue(n.String())
}
panic(fmt.Sprintf("unsupported node kind %d", n.Kind)) Defensive patterns
Strategy: type-guard
Validate before calling
// before calling ToValue
if n.Kind < Null || n.Kind > Undefined {
return fmt.Errorf("node has invalid kind %d", n.Kind)
} Type guard
func hasSupportedKind(n *jsonx.Node) bool {
switch n.Kind {
case jsonx.Null, jsonx.Bool, jsonx.Number, jsonx.String, jsonx.Object, jsonx.Array, jsonx.Undefined:
return true
}
return false
} Try / catch
// Go has no catch for panics in the same goroutine; wrap if embedding:
func safeToValue(n *jsonx.Node, vm *goja.Runtime) (v goja.Value, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("toValue: %v", r)
}
}()
return n.ToValue(vm), nil
} Prevention
- Always set Kind from the package's exported constants, never raw ints
- Add a switch-exhaustion test covering every Node kind
- Keep node-producing and consuming code on the same library version
When it happens
Trigger: Calling ToValue (directly or via KeysComplete) with a Node whose Kind field was never set, was set to a value outside the jsonx kind constants, or came from a third-party constructor that introduced a new kind not yet handled in the switch.
Common situations: Developers adding a new Node kind to the AST who forget to add a case in the ToValue switch; building Node values by hand with a zero-valued Kind; a version mismatch where a caller constructs nodes from another package version.
Related errors
- strconv.ParseFloat: parsing <node value>: invalid syntax (pa
- <error from utils.Unquote(n.Value) unquoting the string node
- <error from utils.Unquote(it.Key) unquoting the object key>
- <error from goja Object.Set> (panic(err))
- <error from json.Marshal of the theme export map> (panic(err
AI-assisted analysis of antonmedv/fx@4f31cd3a0c (2026-09-02).
Data as JSON: /api/errors/4751f9e5760c6f59.
Report an issue: GitHub.