Skip to content

fix: guard limitTaskHistory against negative historyLength - #1039

Merged
kabir merged 1 commit into
a2aproject:mainfrom
ez-lbz:fix/limit-task-history-negative
Aug 11, 2026
Merged

fix: guard limitTaskHistory against negative historyLength#1039
kabir merged 1 commit into
a2aproject:mainfrom
ez-lbz:fix/limit-task-history-negative

Conversation

@ez-lbz

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

Copy link
Copy Markdown
Contributor

What changed

1. Guard limitTaskHistory against negative historyLength

Problem: The guard in limitTaskHistory only checked historyLength >= task.history().size(), which does not catch negative values. A negative historyLength fell through to subList(size - historyLength, size) — i.e. subList(size + 1, size) — throwing IndexOutOfBoundsException. While TaskQueryParams rejects negative values at construction today, limitTaskHistory lacked defensive validation and would crash if a negative value ever reached it.

Fix (server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/DefaultRequestHandler.java):

  • Extended the early-return guard to historyLength < 0, so a negative value returns the task untouched instead of crashing.
  • Semantics are aligned with the Python SDK (apply_history_length): negative → history untouched; 0 → empty history; N >= history size → no limiting. The existing 0 → empty history behavior is preserved (unlike a <= 0 guard, which would have broken it).

Fix (server-common/src/test/java/org/a2aproject/sdk/server/requesthandlers/DefaultRequestHandlerTest.java):

  • testLimitTaskHistoryNegativeHistoryLengthReturnsTaskUnchanged — invokes the private limitTaskHistory via reflection with -1 and asserts no exception is thrown and the task is returned unchanged.
  • testOnGetTaskHistoryLengthLimitsHistoryhistoryLength=2 returns only the 2 most recent messages.
  • testOnGetTaskHistoryLengthZeroReturnsEmptyHistory — locks in that historyLength=0 still returns an empty history.

Behavior change: none for valid inputs (>= 0). Negative historyLength previously crashed; it now returns the task unchanged.

Testing

  • mvn -pl server-common test450 tests run, 0 failures, 0 errors, 0 skipped (BUILD SUCCESS), including the 3 new regression tests.

@kabir kabir 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.

Hi @ez-lbz thank you for the PR.

I've looked and I don't think this is a viable scenario. Essentially, TaskQueryParams has a guard against negative history lengths. And this class is used both to send from the client, as well as used when deserializing requests on the server. So it seems its check will kick in before limitTaskHistory can ever be called.

Let me know if you disagree - there are quite a few PRs to go through today :-)

@ez-lbz

ez-lbz commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for looking at this carefully — your analysis is right that TaskQueryParams rejects negative historyLength values at construction/deserialization today, so the negative path can't currently reach limitTaskHistory through the normal request flow.

The intent here was defense-in-depth: limitTaskHistory is a private helper that would throw IndexOutOfBoundsException on a negative value, and its historyLength parameter isn't bounded by the record validation if the helper is ever called with a value that slips past a future refactor of the validation layer. The fix is one guard condition and doesn't change behavior for valid inputs.

I'm happy to keep it as a defensive measure, or close the PR if you'd prefer not to carry it — your call.

@kabir
kabir merged commit 0900747 into a2aproject:main Aug 11, 2026
13 checks passed
ehsavoie pushed a commit that referenced this pull request Aug 11, 2026
- Fix import ordering of TaskQueryParams in DefaultRequestHandlerTest
- Remove fragile reflection-based test for negative historyLength guard
  (the two public-API tests already exercise the limitTaskHistory path)
- Trim verbose 4-line comment on negative historyLength guard to one line
- Fix Javadoc on bufferFlushDelayMs(): negative values are clamped to 0,
  not returned as the default
- Replace fully-qualified class names with imports in EventQueueTest

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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