Skip to content

fix: preserve explicit zero-length limits in handlers and storage#440

Open
Subhajitdas99 wants to merge 6 commits intoGetBindu:mainfrom
Subhajitdas99:fix/zero-length-limit-handling
Open

fix: preserve explicit zero-length limits in handlers and storage#440
Subhajitdas99 wants to merge 6 commits intoGetBindu:mainfrom
Subhajitdas99:fix/zero-length-limit-handling

Conversation

@Subhajitdas99
Copy link
Copy Markdown
Contributor

@Subhajitdas99 Subhajitdas99 commented Apr 4, 2026

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: Explicit zero-length values like length=0 and history_length=0 were treated as falsy/missing in some handlers and storage paths.
  • Why it matters: This caused inconsistent behavior such as falling back to another parameter or returning full history/results instead of an empty result.
  • What changed: Preserved explicit zero values in handlers, returned empty history/results for zero-length requests, and aligned in-memory and PostgreSQL behavior.
  • What did NOT change (scope boundary): No protocol changes, no schema changes, no auth changes, and no new features beyond zero-limit correctness handling.

Change Type (select all that apply)

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Security hardening
  • Tests
  • Chore/infra

Scope (select all touched areas)

  • Server / API endpoints
  • Extensions (DID, x402, etc.)
  • Storage backends
  • Scheduler backends
  • Observability / monitoring
  • Authentication / authorization
  • CLI / utilities
  • Tests
  • Documentation
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #

User-Visible / Behavior Changes

  • Requests with explicit length=0 now return empty results instead of being treated as missing/falsy.
  • Requests with explicit history_length=0 now return empty history consistently.

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/credentials handling changed? (No)
  • New/changed network calls? (No)
  • Database schema/migration changes? (No)
  • Authentication/authorization changes? (No)
  • If any Yes, explain risk + mitigation:

Verification

Environment

  • OS: Windows
  • Python version: 3.12.9
  • Storage backend: InMemoryStorage targeted directly, PostgreSQL logic reviewed/updated
  • Scheduler backend: Mocked in handler tests

Steps to Test

  1. Run targeted unit tests for context handlers, message handlers, and memory storage.
  2. Verify length=0 is preserved in contexts/list instead of falling back to history_length.
  3. Verify history_length=0 returns empty history and zero-length list calls return empty results.

Expected Behavior

  • Explicit zero limits are preserved and interpreted as valid limits.
  • length=0 returns empty task/context results.
  • history_length=0 returns empty task history.

Actual Behavior

  • Verified the above behavior in targeted tests.
  • Targeted test result: 79 passed.

Evidence (attach at least one)

  • Failing test before + passing after
  • Test output / logs
  • Screenshot / recording
  • Performance metrics (if relevant)

Human Verification (required)

What you personally verified (not just CI):

  • Verified scenarios: Explicit length=0 in context listing, explicit history_length=0 in message scheduling and task history loading, zero-length list behavior in in-memory storage.
  • Edge cases checked: Zero-length values are not replaced by fallback parameters and do not behave like omitted values.
  • What you did NOT verify: Full repository-wide test suite and pre-commit hooks are currently blocked by unrelated existing repo issues, including the known DID __future__ import syntax problem.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Database migration needed? (No)
  • If yes, exact upgrade steps:

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Revert this PR/commit.
  • Files/config to restore: Handler and storage files touched in this PR.
  • Known bad symptoms reviewers should watch for: Requests with zero-length values unexpectedly returning non-empty history/results.

Risks and Mitigations

List only real risks for this PR. If none, write None.

  • Risk: Some callers may have unintentionally relied on old falsy handling of zero values.
    • Mitigation: The new behavior matches explicit parameter intent and adds regression coverage for zero-limit handling.

Checklist

  • Tests pass (uv run pytest)
  • Pre-commit hooks pass (uv run pre-commit run --all-files)
  • Documentation updated (if needed)
  • Security impact assessed
  • Human verification completed
  • Backward compatibility considered

Summary by CodeRabbit

  • Bug Fixes

    • Honor explicit zero for pagination and history parameters: length=0 returns empty lists and history_length=0 yields empty histories.
    • Enforce strict validation for pagination/history inputs: reject booleans, non-integers, and negative values; preserve valid zero values rather than ignoring them.
    • Preserve explicit history_length=0 when scheduling tasks.
  • Tests

    • Added unit tests for zero-length behavior and validation failures across listing, loading, and scheduling.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 4, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Handlers now validate and normalize non-negative integer length/history_length (rejecting bool, non-int, negatives) and preserve explicit zeros. Storage treats length == 0 as empty results and history_length == 0 as an empty history. Tests added for zero and invalid inputs.

Changes

Cohort / File(s) Summary
Context Handler Parameter Logic
bindu/server/handlers/context_handlers.py
Added ContextHandlers._parse_non_negative_length(...); list_contexts prefers params["length"] when present (accepts 0) and validates non-negative integer inputs.
Message Handler Task Scheduling
bindu/server/handlers/message_handlers.py
_submit_and_schedule_task checks for presence of "history_length" instead of truthiness and uses a new parser to validate/reject bool, non-int, or negative values; forwards validated history_length (including 0) to scheduler params only when present.
In-Memory Storage Pagination & History
bindu/server/storage/memory_storage.py
load_task applies truncation when history_length is provided and sets history = [] for history_length == 0. list_tasks, list_tasks_by_context, and list_contexts return [] immediately when length == 0.
Postgres Storage History Truncation
bindu/server/storage/postgres_storage.py
load_task treats history_length == 0 as an explicit request for empty history; positive values still return last N entries, None leaves history unchanged.
Handler Tests
tests/unit/server/handlers/test_context_handlers.py, tests/unit/server/handlers/test_message_handlers.py
Added tests ensuring explicit length: 0/history_length: 0 are preserved and forwarded, and invalid (non-int or negative) inputs raise ValueError and prevent storage/scheduler calls.
Storage Tests
tests/unit/server/storage/test_memory_storage.py
Added tests: load_task(..., history_length=0) yields empty history; list_tasks(length=0) and list_contexts(length=0) return [].

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Handler
    participant Scheduler
    participant Storage

    Client->>Handler: Request (params include length / history_length)
    Handler->>Handler: _parse_non_negative_length(value, field_name)\n(reject bool/non-int/neg, accept 0)
    alt Submit & Schedule flow
        Handler->>Scheduler: run_task(..., history_length maybe 0)
        Scheduler->>Storage: create/load task
        Storage-->>Scheduler: task (history truncated if history_length provided)
    else Listing flow
        Handler->>Storage: list_contexts/list_tasks(length)
        Note right of Storage: if length == 0 -> return []
        Storage-->>Handler: result list
    end
    Handler-->>Client: Response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I checked each zero, not tossed away,
Integers only, no booleans to stray,
Histories emptied when zero's the call,
Lists return nothing when limits are small,
I hop on, tests green — carrot all the way! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main bug fix: preserving explicit zero-length limits in handlers and storage, which is the core change across all modified files.
Description check ✅ Passed The description comprehensively addresses all required template sections including Problem, Why it matters, What changed, Change Type, Scope, User-Visible changes, Security Impact, Verification, Evidence, Human Verification, Compatibility, and Risks.
Docstring Coverage ✅ Passed Docstring coverage is 96.67% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bindu/server/handlers/context_handlers.py`:
- Around line 46-49: The current assignment to length from params may accept
non-integer or negative values; update the logic in context_handlers.py where
length is derived from params (the length variable) to validate and normalize it
before forwarding to storage: ensure length is an int and >= 0 (accept 0),
otherwise clear/omit it (e.g., set to None) so invalid values like "", "0"
(string), or negatives are not forwarded; add a simple type-check/coercion path
only for safe numeric types if desired and add a type hint for the
params/handler signature to reflect an Optional[int] for history_length/length.

In `@bindu/server/handlers/message_handlers.py`:
- Around line 131-132: Validate and sanitize config["history_length"] before
adding it to scheduler_params: ensure the value is an integer and >= 0
(preserving 0), e.g., check isinstance(config["history_length"], int) and
config["history_length"] >= 0; if it's a numeric string you may attempt safe
coercion with int(...) inside a try/except, otherwise skip assignment or
raise/log a clear error; update the code that currently sets
scheduler_params["history_length"] from config to perform this validation and
only assign when the value is a valid non-negative int.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 77c9bf50-8518-451c-a7b3-bd4a4bd0dc97

📥 Commits

Reviewing files that changed from the base of the PR and between 45656ee and 6b83f07.

📒 Files selected for processing (7)
  • bindu/server/handlers/context_handlers.py
  • bindu/server/handlers/message_handlers.py
  • bindu/server/storage/memory_storage.py
  • bindu/server/storage/postgres_storage.py
  • tests/unit/server/handlers/test_context_handlers.py
  • tests/unit/server/handlers/test_message_handlers.py
  • tests/unit/server/storage/test_memory_storage.py

Comment on lines +46 to +49
if "length" in params:
length = params["length"]
else:
length = params.get("history_length")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate length type before forwarding to storage.

This now correctly preserves 0, but it also forwards invalid external values (e.g., "", "0", negative numbers), which can fail in storage calls.

Suggested hardening
         params = request.get("params", {})
-        if "length" in params:
-            length = params["length"]
-        else:
-            length = params.get("history_length")
+        if "length" in params:
+            length = params["length"]
+        else:
+            length = params.get("history_length")
+
+        if length is not None:
+            if not isinstance(length, int) or length < 0:
+                raise TypeError("length must be a non-negative integer or null")

As per coding guidelines: "Validate all external input and use type hints for input validation in Python files".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindu/server/handlers/context_handlers.py` around lines 46 - 49, The current
assignment to length from params may accept non-integer or negative values;
update the logic in context_handlers.py where length is derived from params (the
length variable) to validate and normalize it before forwarding to storage:
ensure length is an int and >= 0 (accept 0), otherwise clear/omit it (e.g., set
to None) so invalid values like "", "0" (string), or negatives are not
forwarded; add a simple type-check/coercion path only for safe numeric types if
desired and add a type hint for the params/handler signature to reflect an
Optional[int] for history_length/length.

Comment thread bindu/server/handlers/message_handlers.py Outdated
@Subhajitdas99
Copy link
Copy Markdown
Contributor Author

I also found that CI setup was failing because uv.lock was out of sync with the repo dependency metadata, so I’ve pushed a lockfile refresh.

The remaining local pre-commit/pytest failure is still caused by the existing unrelated syntax issue in bindu/extensions/did/did_agent_extension.py, not by the zero-length limit changes in this PR.

@Subhajitdas99
Copy link
Copy Markdown
Contributor Author

Good catch. I’ve updated this to validate external limit inputs before forwarding them, while still preserving explicit 0. Invalid values such as strings, booleans, and negative integers are now rejected with a clear ValueError, and I added regression coverage for those cases.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
bindu/server/handlers/message_handlers.py (1)

58-67: Consider extracting shared validation logic.

This validation method duplicates _parse_non_negative_length in context_handlers.py. A shared utility (e.g., in bindu/utils/validation.py) could reduce duplication.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindu/server/handlers/message_handlers.py` around lines 58 - 67, Extract the
duplicated validation logic into a shared utility function (e.g.,
validate_non_negative_int) in a new module bindu/utils/validation.py and update
both _parse_non_negative_history_length (in message_handlers.py) and
_parse_non_negative_length (in context_handlers.py) to delegate to that utility;
the shared function should accept the raw value and a field name or message,
perform the same checks (None -> None, reject bool, non-int, or negative ->
raise ValueError with a clear message), and return the validated int so both
handler methods become one-line wrappers calling validate_non_negative_int.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bindu/server/handlers/message_handlers.py`:
- Around line 142-145: The code assigns the result of
_parse_non_negative_history_length (which may return int or None) directly into
scheduler_params["history_length"], causing a type error for TaskSendParams
which expects an int; change the logic in the block that handles
config["history_length"] so you call
self._parse_non_negative_history_length(config["history_length"]) and only set
scheduler_params["history_length"] when the parsed value is not None (i.e., skip
the assignment if parsing returns None) to ensure TaskSendParams.history_length
remains an int.

---

Nitpick comments:
In `@bindu/server/handlers/message_handlers.py`:
- Around line 58-67: Extract the duplicated validation logic into a shared
utility function (e.g., validate_non_negative_int) in a new module
bindu/utils/validation.py and update both _parse_non_negative_history_length (in
message_handlers.py) and _parse_non_negative_length (in context_handlers.py) to
delegate to that utility; the shared function should accept the raw value and a
field name or message, perform the same checks (None -> None, reject bool,
non-int, or negative -> raise ValueError with a clear message), and return the
validated int so both handler methods become one-line wrappers calling
validate_non_negative_int.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0dda1381-be75-4b2f-95ab-5b61a7f52729

📥 Commits

Reviewing files that changed from the base of the PR and between 6b83f07 and bf73535.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • bindu/server/handlers/context_handlers.py
  • bindu/server/handlers/message_handlers.py
  • tests/unit/server/handlers/test_context_handlers.py
  • tests/unit/server/handlers/test_message_handlers.py
✅ Files skipped from review due to trivial changes (1)
  • tests/unit/server/handlers/test_context_handlers.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unit/server/handlers/test_message_handlers.py

Comment thread bindu/server/handlers/message_handlers.py Outdated
@Subhajitdas99
Copy link
Copy Markdown
Contributor Author

I checked the failing CI log.

There was one PR-local typing issue in message_handlers.py around assigning history_length, and I’ve pushed a fix for that.

The remaining failures are still coming from unrelated repository-wide issues outside this PR, including:

  • bindu/extensions/did/did_agent_extension.py syntax error
  • invalid YAML in examples/ag2_research_team/.../skill.yaml
  • detect-secrets hits in examples/pdf_research_agent/...
  • formatting/pre-commit changes on unrelated files

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bindu/server/handlers/message_handlers.py`:
- Around line 149-154: The ValueError thrown by
_parse_non_negative_history_length (propagating through
_submit_and_schedule_task) is currently reaching the top-level RPC handler and
being mapped to InternalError; catch that validation error earlier and convert
it to the RPC-level invalid-parameters error instead. Specifically, in the call
site where you set scheduler_params["history_length"] (the block using
_parse_non_negative_history_length and TaskSendParams["history_length"]), wrap
the parse in a try/except that catches ValueError and raises the RPC
InvalidParamsError (or translate into the same error type the a2a_protocol
handler would use for invalid params) so explicit bad input yields code
-32602/status 400 rather than an InternalError. Ensure you reference
_parse_non_negative_history_length and _submit_and_schedule_task when making the
change so the conversion happens before the exception reaches a2a_protocol's
top-level mapper.

In `@tests/unit/server/handlers/test_context_handlers.py`:
- Around line 59-75: The test test_list_contexts_preserves_explicit_zero_length
asserts the mock_storage.list_contexts call without the default owner_did
keyword; update the assertion to include owner_did=None because
ContextHandlers.list_contexts forwards owner_did=caller_did (caller_did defaults
to None when omitted). Change the final assertion on mock_storage.list_contexts
to assert it was called with length 0 and owner_did=None (use the exact keyword
name owner_did) so it matches the actual call shape from handler.list_contexts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0a7a5a9f-3905-4835-8f31-7652f953cbeb

📥 Commits

Reviewing files that changed from the base of the PR and between 968c714 and 4cef6cf.

📒 Files selected for processing (5)
  • bindu/server/handlers/context_handlers.py
  • bindu/server/handlers/message_handlers.py
  • bindu/server/storage/memory_storage.py
  • bindu/server/storage/postgres_storage.py
  • tests/unit/server/handlers/test_context_handlers.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • bindu/server/storage/postgres_storage.py
  • bindu/server/storage/memory_storage.py
  • bindu/server/handlers/context_handlers.py

Comment thread bindu/server/handlers/message_handlers.py
Comment thread tests/unit/server/handlers/test_context_handlers.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bindu/server/handlers/message_handlers.py (1)

135-158: ⚠️ Potential issue | 🟠 Major

Validate history_length before creating the task.

Invalid external input is currently rejected only after storage.submit_task(...), so a bad configuration.history_length can persist an unscheduled/orphan task. Parse the config before any storage side effect.

As per coding guidelines, "Validate all external input and use type hints for input validation in Python files".

🐛 Proposed fix: move validation before task creation
         """Submit task to storage and schedule it with shared send/stream logic."""
         message = request_params["message"]
         context_id = self.context_id_parser(message.get("context_id"))
 
+        config = request_params.get("configuration", {})
+        history_length: int | None = None
+        if "history_length" in config:
+            try:
+                history_length = self._parse_non_negative_history_length(
+                    config["history_length"]
+                )
+            except ValueError as exc:
+                from bindu.common.protocol.types import InvalidParamsError
+
+                raise InvalidParamsError(str(exc)) from exc
+
         task: Task = await self.storage.submit_task(
             context_id, message, caller_did=caller_did
         )
 
         scheduler_params: TaskSendParams = TaskSendParams(
@@
             message=message,
         )
 
-        config = request_params.get("configuration", {})
-        if "history_length" in config:
-            try:
-                history_length = self._parse_non_negative_history_length(
-                    config["history_length"]
-                )
-            except ValueError as exc:
-                from bindu.common.protocol.types import InvalidParamsError
-                raise InvalidParamsError(str(exc)) from exc
-            if history_length is not None:
-                scheduler_params["history_length"] = history_length
+        if history_length is not None:
+            scheduler_params["history_length"] = history_length
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindu/server/handlers/message_handlers.py` around lines 135 - 158, The
history_length validation must run before persisting a Task to avoid creating
orphan/unscheduled tasks: move the config parsing block that calls
self._parse_non_negative_history_length and raises InvalidParamsError (using
InvalidParamsError from bindu.common.protocol.types) to run before calling
self.storage.submit_task; construct/validate history_length from
request_params.get("configuration", {}) first, then call self.context_id_parser
and await self.storage.submit_task, and finally populate TaskSendParams
(TaskSendParams, task["id"], scheduler_params) with the validated history_length
if present.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@bindu/server/handlers/message_handlers.py`:
- Around line 135-158: The history_length validation must run before persisting
a Task to avoid creating orphan/unscheduled tasks: move the config parsing block
that calls self._parse_non_negative_history_length and raises InvalidParamsError
(using InvalidParamsError from bindu.common.protocol.types) to run before
calling self.storage.submit_task; construct/validate history_length from
request_params.get("configuration", {}) first, then call self.context_id_parser
and await self.storage.submit_task, and finally populate TaskSendParams
(TaskSendParams, task["id"], scheduler_params) with the validated history_length
if present.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 08ee825d-4fbc-46c6-9479-3b7ce76a78c7

📥 Commits

Reviewing files that changed from the base of the PR and between 4cef6cf and 2c64bcf.

📒 Files selected for processing (2)
  • bindu/server/handlers/message_handlers.py
  • tests/unit/server/handlers/test_context_handlers.py
✅ Files skipped from review due to trivial changes (1)
  • tests/unit/server/handlers/test_context_handlers.py

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.

1 participant