Skip to content

fix(tools): return a structured error when RestApiTool is missing a required path param - #7283

Open
chelsealong wants to merge 2 commits into
google:mainfrom
chelsealong:fix-resttool-missing-path-param
Open

chelsealong wants to merge 2 commits into
google:mainfrom
chelsealong:fix-resttool-missing-path-param

Conversation

@chelsealong

Copy link
Copy Markdown
Contributor

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

Problem:
FunctionTool returns {"error": ...} when a mandatory argument is missing so the model can see the failure and retry. RestApiTool does not: _prepare_request_params fills path_params only for keys the caller actually supplied, then does self.endpoint.path.format(**path_params). If a required path parameter is omitted (and has no schema default), the format template still has an unfilled {placeholder}, so str.format raises an uncaught KeyError with the OpenAPI parameter's original name (e.g. 'userId'). RestApiTool.call() only catches httpx.TimeoutException / httpx.HTTPStatusError, so this KeyError propagates out of the tool and aborts the whole agent invocation instead of giving the model a retryable error.

Solution:
Wrap the self._prepare_request_params(...) call in RestApiTool.call() in a try/except KeyError, mirroring the structured-error pattern FunctionTool already uses for missing mandatory args. On a missing path parameter, call() now returns {"error": "Tool <name> execution failed. ... Missing required path parameter '<name>'."} instead of raising.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Added test_call_missing_required_path_param_returns_error, which builds a RestApiTool for GET /users/{userId}/messages with a required userId path parameter that has no default, calls it with no args, and asserts the tool returns a structured {"error": ...} naming userId instead of raising, and that no HTTP request is made.

Regression proof — reverting only the source fix and running the new test:

$ git checkout HEAD~1 -- src/google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py
$ pytest tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py -k missing_required_path_param -q
...
E     KeyError: 'userId'
src/google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py:427: KeyError
1 failed, 81 deselected in 1.23s

With the fix restored:

$ pytest tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py -k missing_required_path_param -q
1 passed, 81 deselected in 2.77s

$ pytest tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py -q
82 passed, 17 warnings in 2.01s

$ pytest tests/unittests/tools/ -q
2470 passed, 808 warnings in 53.18s

Formatting/lint on the changed files:

$ python -m isort --settings-path pyproject.toml --check --diff <files>
(no changes)
$ python -m pyink --config pyproject.toml --check --diff <files>
All done! 2 files would be left unchanged.
$ python -m ruff check --config pyproject.toml <files>
All checks passed!

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have added tests that prove my fix is effective.
  • New and existing unit tests pass locally with my changes.
  • Any dependent changes have been merged and published in downstream modules.

AI assistance disclosure

This change was prepared with the assistance of Claude Code (Anthropic), under human review before submission.

🤖 Generated with Claude Code

…equired path param

RestApiTool._prepare_request_params substitutes filled path parameters
into self.endpoint.path.format(**path_params). An omitted required path
parameter leaves the template key unset, so format() raises an
uncaught KeyError that aborts the whole agent invocation instead of
giving the model a retryable {"error": ...} result, unlike
FunctionTool which already reports missing mandatory args this way.

call() now catches KeyError from _prepare_request_params and returns
a structured error naming the missing path parameter.
Resolve conflict in rest_api_tool.py: upstream/main added an
InputValidationError catch and a _format_error_response helper for a
separate path-traversal fix. Keep both the KeyError catch (missing
required path parameter) and the InputValidationError catch, and
route the KeyError message through the new _format_error_response
helper for consistency.
@chelsealong

Copy link
Copy Markdown
Contributor Author

Merged upstream/main to resolve the conflict in rest_api_tool.py (main added an InputValidationError catch + a _format_error_response helper for a separate path-traversal fix). Kept this PR's KeyError catch for the missing path parameter, routed its message through the new _format_error_response helper, and re-ran the full tests/unittests/tools/ suite (2531 passed) plus isort/pyink/ruff on the touched file — all clean.

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.

RestApiTool raises uncaught KeyError when a required path param is omitted

2 participants