Skip to content

A --jq expression that inspects a type panics: jqUnwrapNumbers hands gojq an int64 #749

Closed

Description

@David-Noble-at-work

Feature: #833 — Renderings: the pipeline from result value to stdout

A --jq expression that inspects a value's type crashes the process.

Reproduction

$ devlore-test run --jq '[paths(scalars) as $p | "\($p|map(tostring)|join(".")): \(getpath($p))"]' \
    -o value test_hello.star

panic: invalid type: int64 (1)

goroutine 1 [running]:
github.com/itchyny/gojq.TypeOf(...)  type.go:29
github.com/itchyny/gojq.funcType(...) func.go:517

Any expression reaching TypeOf over an integer does it: tostring, type, tonumber, and the arithmetic
paths, among others.

Cause

gojq's accepted types are exactly nil, bool, int, float64, *big.Int, json.Number, string,
[]any, map[string]any -- type.go:20-30, whose default branch is the panic above.

jqUnwrapNumbers (pkg/result/jq_filter.go:121) hands it something else:

case json.Number:
    if i, err := v.Int64(); err == nil {
        return i          // int64, which is NOT in gojq's table
    }

v.Int64() returns int64. Every integer that survives a --jq expression is therefore a value gojq will
panic on the moment anything asks its type.

The conversion is not needed

gojq handles json.Number natively and everywhere -- comparison (compare.go:67), encoding
(encoder.go:66), and a dozen sites across func.go including tostring, tonumber, and the arithmetic
operators. option.go:36 states the contract: "On handling numbers, take account of int, float64, *big.Int,
and json.Number."

The function's own comment claims it "keeps == comparisons stable across integer and float". That does not
hold: compare.go:67 puts json.Number in the same case as int and float64, so gojq already compares
them uniformly.

It is also lossy

Int64() fails for a number beyond int64, and the fallback is Float64(), which rounds. An integer past
2^53 loses digits inside the filter -- the same defect #712 records against the document codec, and the
reason normalize deliberately keeps json.Number for the presenters.

Fix

Delete jqUnwrapNumbers and pass the normalized value to gojq unchanged. That removes the panic, removes the
rounding, and removes a conversion gojq never wanted.

Verification

  • The reproduction above completes and prints flattened paths.
  • --jq '.unit_count | tostring' returns the number as a string rather than panicking.
  • An integer past 2^53 survives a --jq expression with its digits intact.

Metadata

Metadata

Labels

Area:CLICommand-line interfaceArea:ErrorHandlingError handling and propagationEpic:CommandLineOne output convention across every CLI in the suitebugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions