ping JSON-RPC reply: timestamp wire type differs across platforms at the same CLI version (1.0.51)
Summary
At the same CLI version (1.0.51 / 1.0.51-2) the ping JSON-RPC
reply serializes the timestamp field with two incompatible JSON
types depending on the host platform:
| Host |
copilot --version |
Raw timestamp bytes |
JSON type |
| Windows |
GitHub Copilot CLI 1.0.51-2 |
1779352370134 |
NUMBER (epoch ms, fits int64) |
| Linux (container) |
GitHub Copilot CLI 1.0.51 |
"2026-05-21T08:29:54.042Z" |
STRING (ISO 8601) |
Both samples are real captures via a hand-rolled JSON-RPC stdio harness
(no SDK, no wrapper) running the official flags
--headless --no-auto-update --log-level debug --stdio.
This breaks every typed downstream that expects a stable schema — most
notably copilot-sdk/go (filed sibling issue), where
PingResponse.Timestamp is int64 and the SDK refuses to start on
Linux at 1.0.51 with:
json: cannot unmarshal string into Go struct field PingResponse.timestamp of type int64
Beyond the SDK breakage, having the same RPC return two unrelated value
types depending on platform is a substantive schema violation in its own
right.
Reproduction
Tiny Go program at tmp/sdk-repro/cmd/captureping (no SDK
dependency — only encoding/json + os/exec):
$ go run ./cmd/captureping
=== HOST ===
go_os=... go_arch=... go_version=...
copilot_path=...
copilot_version=GitHub Copilot CLI 1.0.51...
spawning: copilot [--headless --no-auto-update --log-level debug --stdio]
writing request: {"id":1,"jsonrpc":"2.0","method":"ping","params":{"message":""}}
=== RAW RESPONSE BYTES ===
{"jsonrpc":"2.0","id":1,"result":{...}}
=== RESULT FIELD KINDS ===
message raw="pong" kind=STRING
protocolVersion raw=3 kind=NUMBER
timestamp raw=... kind=NUMBER | STRING
Run on both platforms with the same flags and compare the final
timestamp ... kind= line.
Actual captures
Windows host, copilot.bat 1.0.51-2:
copilot_version=GitHub Copilot CLI 1.0.51-2.
=== RAW RESPONSE BYTES ===
{"jsonrpc":"2.0","id":1,"result":{"message":"pong","timestamp":1779352370134,"protocolVersion":3}}
=== RESULT FIELD KINDS ===
message raw="pong" kind=STRING
protocolVersion raw=3 kind=NUMBER
timestamp raw=1779352370134 kind=NUMBER
Linux container, copilot 1.0.51:
copilot_version=GitHub Copilot CLI 1.0.51
=== RAW RESPONSE BYTES ===
{"jsonrpc":"2.0","id":1,"result":{"message":"pong","timestamp":"2026-05-21T08:29:54.042Z","protocolVersion":3}}
=== RESULT FIELD KINDS ===
message raw="pong" kind=STRING
protocolVersion raw=3 kind=NUMBER
timestamp raw="2026-05-21T08:29:54.042Z" kind=STRING
Why this is the CLI's problem, not the SDK's
- The CLI is the authoritative definition of the wire protocol. Whatever
it sends is the schema for all client SDKs (Node, .NET, Python, Go).
- Asking every SDK to grow a per-field union type to absorb platform
inconsistencies pushes downstream complexity outward forever.
- The platform delta proves the inconsistency is internal to the CLI
build pipeline (most likely a Date#toJSON() vs
Date.now() / BigInt codepath that gets compiled / bundled
differently per OS target).
Suggested fix
Pick one canonical wire representation for result.timestamp and
emit it consistently on every platform. Either:
- A. Epoch milliseconds as a JSON number (matches what the Go SDK's
PingResponse.Timestamp int64 and the field's existing
semantics imply — and what the Windows build already does).
- B. ISO 8601 string (more self-documenting, but requires breaking
schema changes in all SDKs).
(A) is the cheaper fix and aligns with what existing typed SDKs expect.
Either way, please also add a wire-format regression test that asserts
the JSON typeof of every public RPC result field, so that future
serializer / bundler changes can't reintroduce a platform-specific
divergence silently.
Sibling issue
github/copilot-sdk — request a tolerant UnmarshalJSON on
PingResponse so the Go SDK can survive both wire shapes during any
rollout / mixed-fleet window. (URL to be filled in once both issues are
opened.)
pingJSON-RPC reply:timestampwire type differs across platforms at the same CLI version (1.0.51)Summary
At the same CLI version (
1.0.51/1.0.51-2) thepingJSON-RPCreply serializes the
timestampfield with two incompatible JSONtypes depending on the host platform:
copilot --versiontimestampbytesGitHub Copilot CLI 1.0.51-21779352370134GitHub Copilot CLI 1.0.51"2026-05-21T08:29:54.042Z"Both samples are real captures via a hand-rolled JSON-RPC stdio harness
(no SDK, no wrapper) running the official flags
--headless --no-auto-update --log-level debug --stdio.This breaks every typed downstream that expects a stable schema — most
notably
copilot-sdk/go(filed sibling issue), wherePingResponse.Timestampisint64and the SDK refuses to start onLinux at 1.0.51 with:
Beyond the SDK breakage, having the same RPC return two unrelated value
types depending on platform is a substantive schema violation in its own
right.
Reproduction
Tiny Go program at
tmp/sdk-repro/cmd/captureping(no SDKdependency — only
encoding/json+os/exec):Run on both platforms with the same flags and compare the final
timestamp ... kind=line.Actual captures
Windows host,
copilot.bat1.0.51-2:Linux container,
copilot1.0.51:Why this is the CLI's problem, not the SDK's
it sends is the schema for all client SDKs (Node, .NET, Python, Go).
inconsistencies pushes downstream complexity outward forever.
build pipeline (most likely a
Date#toJSON()vsDate.now()/BigIntcodepath that gets compiled / bundleddifferently per OS target).
Suggested fix
Pick one canonical wire representation for
result.timestampandemit it consistently on every platform. Either:
PingResponse.Timestamp int64and the field's existingsemantics imply — and what the Windows build already does).
schema changes in all SDKs).
(A) is the cheaper fix and aligns with what existing typed SDKs expect.
Either way, please also add a wire-format regression test that asserts
the JSON
typeofof every public RPC result field, so that futureserializer / bundler changes can't reintroduce a platform-specific
divergence silently.
Sibling issue
github/copilot-sdk— request a tolerantUnmarshalJSONonPingResponseso the Go SDK can survive both wire shapes during anyrollout / mixed-fleet window. (URL to be filled in once both issues are
opened.)