Skip to content

fix(types): preserve unknown enum integer values in codecs - #657

Open
Varun-S10 wants to merge 1 commit into
a2aproject:mainfrom
Varun-S10:fix/issue-640
Open

fix(types): preserve unknown enum integer values in codecs#657
Varun-S10 wants to merge 1 commit into
a2aproject:mainfrom
Varun-S10:fix/issue-640

Conversation

@Varun-S10

Copy link
Copy Markdown
Contributor

Description

Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

  • Follow the CONTRIBUTING Guide.
  • Make your Pull Request title in the https://www.conventionalcommits.org/ specification.
    • Important Prefixes for release-please:
      • fix: which represents bug fixes, and correlates to a SemVer patch.
      • feat: represents a new feature, and correlates to a SemVer minor.
      • feat!:, or fix!:, refactor!:, etc., which represent a breaking change (indicated by the !) and will result in a SemVer major.
  • Ensure the tests and linter pass
  • Appropriate docs were updated (if necessary)

Fixes #640 🦕


What was the bug?

In the proto3 JSON specification, enums (such as TaskState and Role) must remain forward-compatible. When an SDK receives an unknown or newly added numeric enum value from a newer peer (e.g. state: 99 or role: 42), it must preserve that integer value so it can be safely passed through proxies, gateways, and relays without data loss.

Previously in @a2a-js/sdk:

  • taskStateFromJSON and roleFromJSON mapped any unrecognized numeric value to UNRECOGNIZED (-1).
  • taskStateToJSON and roleToJSON then serialized this into the literal string "UNRECOGNIZED".
  • When an a2a-python peer received {"state": "UNRECOGNIZED"}, it threw a ParseError: Invalid enum value UNRECOGNIZED. The original numeric value 99 was destroyed, breaking interoperability.

How is it fixed?

  1. src/types/pb/a2a.ts:
    • Updated taskStateFromJSON and roleFromJSON default switch cases to preserve unknown integer numbers (typeof object === "number" ? object : UNRECOGNIZED).
    • Updated taskStateToJSON and roleToJSON to return string | number so that unknown enum integers are emitted directly as numbers instead of "UNRECOGNIZED".
  2. src/client/transports/rest_transport.ts & src/samples/cli.ts:
    • Wrapped taskStateToJSON in String(...) when formatting URL query parameters and CLI logs.
  3. test/types/enums.spec.ts:
    • Added unit tests for TaskState and Role covering known string names, known numbers, unknown numeric integer preservation, and message round-tripping.

Verification

  • Unknown enum numbers (state: 99, role: 42) round-trip cleanly as integers (99, 42) instead of collapsing into "UNRECOGNIZED".
  • Known enum values continue to serialize as string names (e.g. "TASK_STATE_WORKING", "ROLE_USER").
  • Unit tests in test/types/enums.spec.ts passed (10/10).
  • Full test suite (npm test) passed (69/69 test files, 1,497 tests).
  • ESLint and TypeScript checks (npm run lint) passed with 0 errors.
  • Build and bundle checks (npm run build && npm run test-build) passed cleanly.

@Varun-S10
Varun-S10 requested a review from a team as a code owner August 14, 2026 07:02
@github-actions

Copy link
Copy Markdown

🧪 Code Coverage

⬇️ Download Full Report

No coverage changes.

Generated by coverage-comment.yml

@bartek-gralewicz

Copy link
Copy Markdown
Contributor

Hello @Varun-S10,

Thank you for looking into this and proposing a fix. The issue is real but the fix proposed in this PR is difficult to maintain. The changes made to the src/types/pb/a2a.ts should be reverted as this file is autogenerated and should not be modified manually (https://github.com/a2aproject/a2a-js/blob/main/src/types/pb/a2a.ts#L1). Any modification to this file would need to be reapplied with each new from-proto-generation.

A more sustainable approach would be to create codecs file that would reexport from original pb/a2a.ts with fixed methods where relevant. Additionally, src/index would export these codecs instead of pb/a2a.ts. Direct imports from pb/a2a.ts would be restricted using eslint.config.mjs.

What do you think about such approach?

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.

[Bug]: unknown enum values become the string "UNRECOGNIZED", which a2a-python rejects

2 participants