Skip to content

[Feature][High] Fix cross-SDK JSON serialization mismatch, httpx resource leak, and missing network error handling #24

@numbers-official

Description

@numbers-official

Summary

Three high-priority correctness and reliability issues that affect SDK interoperability and production stability.

1. JSON Serialization Inconsistency in Integrity Proof Signing (Both SDKs)

Files:

  • ts/src/crypto.ts:44 — uses JSON.stringify(proof)
  • python/numbersprotocol_capture/crypto.py:71 — uses json.dumps(proof_dict, separators=(",", ":"))

The integrity SHA is computed by hashing the JSON-serialized proof. The TypeScript SDK uses JSON.stringify(proof) while the Python SDK uses json.dumps with explicit compact separators. Neither SDK sorts keys deterministically. If a user signs with one SDK and verifies with another, any serialization difference produces a different integritySha, causing silent signature verification failure.

Additionally, in ts/src/client.ts:257, the proof is re-serialized independently from the hash computation at crypto.ts:44, creating a fragile coupling where two separate JSON.stringify calls must produce identical output.

Suggested fix:

  • Both SDKs: Sort keys explicitly (JSON.stringify(proof, Object.keys(proof).sort()) in TS, json.dumps(..., sort_keys=True) in Python).
  • Serialize the proof once and reuse the serialized string for both hashing and the form payload.

2. Python httpx.Client Resource Leak Risk

File: python/numbersprotocol_capture/client.py:131-159

The Capture.__init__ creates self._client = httpx.Client(timeout=30.0) but there is no __del__ finalizer. Users who do not use the context manager (with statement) and never call .close() leak the connection pool. There is no ResourceWarning or documentation warning about this.

Suggested fix:

  • Add __del__ that calls self._client.close() as a safety net.
  • Alternatively, use lazy initialization (create httpx.Client on first request).
  • At minimum, emit a ResourceWarning if the client is garbage-collected without being closed.

3. TypeScript fetch() Calls Lack Network Error Wrapping

Files:

  • ts/src/client.ts:176 (request method)
  • ts/src/client.ts:374 (getHistory)
  • ts/src/client.ts:430 (getAssetTree)
  • ts/src/client.ts:520 (searchAsset)
  • ts/src/client.ts:576 (searchNft)

None of the five fetch() call sites wrap network errors in the SDK's NetworkError type. When DNS resolution fails, TLS handshake fails, or the network is down, fetch() throws a raw TypeError (browsers) or generic Error (Node.js). By contrast, the Python SDK correctly catches httpx.RequestError and wraps it.

Suggested fix:

try {
  const response = await fetch(url, { method, headers, body });
} catch (error) {
  throw new NetworkError(`Network error: ${error instanceof Error ? error.message : error}`);
}

Apply this consistently across all five call sites.


Impact: Finding 1 could cause silent cross-SDK signature verification failures in production. Finding 2 causes connection pool exhaustion in long-running applications. Finding 3 causes unhandled promise rejections and poor error diagnostics.

Generated by Health Monitor with Omni

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions