Skip to content

fix(cli): Restore 64-bit default handling in the proto target - #2409

Open
Jaybhade wants to merge 1 commit into
protobufjs:masterfrom
Jaybhade:fix/proto-target-long-defaults
Open

fix(cli): Restore 64-bit default handling in the proto target#2409
Jaybhade wants to merge 1 commit into
protobufjs:masterfrom
Jaybhade:fix/proto-target-long-defaults

Conversation

@Jaybhade

@Jaybhade Jaybhade commented Aug 9, 2026

Copy link
Copy Markdown

pbjs -t proto2 (and -t proto3) aborts with TypeError: util.longNeq is not a function for any proto2 field of a 64-bit type that carries an explicit default:

syntax = "proto2";

message Feature {
    optional uint64 id = 1 [default = 0];
}
TypeError: util.longNeq is not a function
    at cli/targets/proto.js:254:41
    at buildFieldOptions (cli/targets/proto.js:245:10)
    at buildField (cli/targets/proto.js:221:16)

buildFieldOptions was added in 4affa1b (Nov 2016) and calls util.longNeq to decide whether a resolved default is just the type's implicit default and can be dropped. 39bc103 (Jan 2017) removed util.longNeq as "now unused" — the call site here was missed, and it is the only remaining reference to it in the tree. So the branch has never been reachable without throwing on any released 6.x/7.x/8.x.

tests/data/mapbox/vector_tile.proto, already in this repo, is enough to trigger it (optional uint64 id = 1 [ default = 0 ];), so the failure hits a very ordinary real-world schema. This was reported in #809; it was closed as a stale-static-code problem, but @jhherren pointed at this exact line afterwards and it stayed.

Fix

Compare the resolved default against the type default with util.longToHash. The old helper existed because the two sides are not the same shape — field.defaultValue is a Long for 64-bit fields while types.defaults[field.type] is the number 0 — and longToHash normalises both through LongBits, so the comparison keeps working for signed, unsigned and negative values.

Behaviour after the fix matches what 32-bit fields already do: a default equal to the implicit default is omitted, anything else is emitted.

$ node cli/bin/pbjs -t proto2 tests/data/mapbox/vector_tile.proto
...
    message Feature {

        optional uint64 id = 1;
        repeated uint32 tags = 2 [packed=true];
        optional GeomType type = 3 [default=UNKNOWN];
        repeated uint32 geometry = 4 [packed=true];
    }

Tests

Added proto2 64 bit field defaults to tests/cli-proto.js, covering the implicit-default case (dropped), positive and negative 64-bit defaults (emitted) and a 32-bit default alongside them (unchanged). It fails with the TypeError above on master and passes with the fix.

npm run lint and npm test are green (3164 assertions, up from 3162).

One thing this deliberately does not address: a 64-bit default larger than Number.MAX_SAFE_INTEGER is already lost before it reaches the target, because parse.js stores option values as JS numbers — [default = 18446744073709551615] comes out as [default=18446744073709552000]. That is a separate problem in the parser rather than in this branch, so I left it alone.

buildFieldOptions still calls util.longNeq, which was removed in 39bc103.
Any proto2 field of a 64-bit type carrying an explicit default therefore
makes pbjs -t proto2 / -t proto3 abort with a TypeError, including on
tests/data/mapbox/vector_tile.proto.

Compare the resolved default against the type default through longToHash
instead, which handles the number/Long mix the old helper existed for, so
a default equal to the implicit one is dropped just as it already is for
32-bit fields and any other default is emitted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant