Skip to content

fix: enforce upper bound on history_length - #1177

Open
ez-lbz wants to merge 2 commits into
a2aproject:mainfrom
ez-lbz:fix/history-length-upper-bound
Open

fix: enforce upper bound on history_length#1177
ez-lbz wants to merge 2 commits into
a2aproject:mainfrom
ez-lbz:fix/history-length-upper-bound

Conversation

@ez-lbz

@ez-lbz ez-lbz commented Aug 10, 2026

Copy link
Copy Markdown

What changed

1. Enforce an upper bound on historyLength

Problem: validate_history_length() in src/a2a/utils/task.py only rejected negative values. A client could send historyLength=999999999 and the server would materialize the full task history for every matching task (in tasks/get, tasks/list, and message/send), allowing an unbounded-history read via an absurdly large parameter.

Fix (src/a2a/utils/task.py):

  • Added MAX_HISTORY_LENGTH = 1000 with a comment explaining the cap is a pragmatic bound aligned with the other A2A SDKs' "large value ≈ return everything available" semantics.
  • validate_history_length() now raises InvalidParamsError when history_length > MAX_HISTORY_LENGTH (in addition to the existing negative-value check). The validation already runs at the entry of on_get_task, on_list_tasks, and on_message_send (V1) and their V2 counterparts, so the cap applies to all JSON-RPC / REST / gRPC paths without further changes.

Testing

  • ./.venv/Scripts/python -m pytest tests/utils/test_task.py tests/server/request_handlers/test_default_request_handler.py tests/server/request_handlers/test_default_request_handler_v2.py -q150 passed (includes 8 new regression tests: validate_history_length unit tests plus handler-level history_length over-limit rejection for on_get_task and on_message_send).
  • ./.venv/Scripts/python -m ruff check on modified files: clean.
  • Behavior change: requests with historyLength above 1000 now return InvalidParamsError instead of returning full history. Requests at or below the cap are unaffected (existing tests all use values ≤ 10).

@ez-lbz
ez-lbz requested a review from a team as a code owner August 10, 2026 16:09
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

🧪 Code Coverage (vs main)

⬇️ Download Full Report

Base PR Delta
src/a2a/server/events/event_queue_v2.py 91.79% 91.28% 🔴 -0.51%
src/a2a/utils/task.py 95.16% 95.59% 🟢 +0.43%
src/a2a/utils/telemetry.py 91.47% 90.70% 🔴 -0.78%
Total 93.00% 92.98% 🔴 -0.02%

Generated by coverage-comment.yml

@mykytanetipa mykytanetipa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The history_length cap is a reasonable idea, but it's a public-facing behavioral change, so it should be reviewed and accepted by the A2A spec maintainers first. Please open a spec proposal PR at https://github.com/a2aproject/A2A before implementing it in the SDK.

Comment thread src/a2a/utils/task.py
@@ -25,9 +36,13 @@ def HasField(self, field_name: Literal['history_length']) -> bool: # noqa: N802


def validate_history_length(config: HistoryLengthConfig | None) -> None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description states that right now server "allowing an unbounded-history read via an absurdly large parameter", but the change into validate_history_length doesn't affect this, full task history will still be loaded in memory.

example on_get_task:

# param validation happens here:
validate_history_length(params)                                                    
...
# task is loaded with full history here:
task: Task | None = await self.task_store.get(task_id, context)  
...
# history cap is applied here:
return apply_history_length(task, params)                                   

Comment thread src/a2a/utils/task.py
from a2a.utils.errors import InvalidParamsError


MAX_HISTORY_LENGTH = 1000

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd avoid setting MAX_HISTORY_LENGTH just as a global constant. If this change lands it should be configurable, opt-in, with None default and set by some server config

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.

2 participants