Skip to content

fix: crash when a tool parameter is named properties (create_tool_from_function, @tool, ComponentTool)#12037

Merged
sjrl merged 2 commits into
deepset-ai:mainfrom
sohumt123:fix-tool-schema-parameter-named-properties
Jul 20, 2026
Merged

fix: crash when a tool parameter is named properties (create_tool_from_function, @tool, ComponentTool)#12037
sjrl merged 2 commits into
deepset-ai:mainfrom
sohumt123:fix-tool-schema-parameter-named-properties

Conversation

@sohumt123

Copy link
Copy Markdown
Contributor

Related Issues

  • No existing issue: searched open and closed issues/PRs for remove_title_from_schema, 'str' object has no attribute 'items', and tool-schema AttributeError and found no report of this bug.

Proposed Changes:

Creating a Tool from any function whose signature has a parameter named properties crashes with AttributeError: 'str' object has no attribute 'items'. All of create_tool_from_function, the @tool decorator, and ComponentTool (which imports the same helper) are affected, and a parameter named properties is quite realistic for LLM tools (e.g. "set/update entity properties" tools for graph or DB backends):

from typing import Annotated
from haystack.tools import tool

@tool
def set_properties(
    entity_id: Annotated[str, "the entity"],
    properties: Annotated[dict, "properties to set"],
) -> str:
    """Set properties on an entity."""
    return "ok"
# AttributeError: 'str' object has no attribute 'items'
#   (raised from _remove_title_from_schema, haystack/tools/from_function.py:346)

Root cause: _remove_title_from_schema special-cases key == "properties" and isinstance(value, dict) and "title" in value so that a property named title is not deleted. But the keys of a properties mapping are property names, not schema keywords, and the guard only fires when a property named title happens to exist. When a property is named properties, one level deeper the iteration hits key == "properties" whose value is that property's Pydantic sub-schema — which always contains a title keyword — so the branch triggers and recurses into raw scalar values like "Properties" and "string", calling .items() on a str.

Fix: the properties branch now applies unconditionally and only recurses into dict sub-schemas, so property names are never interpreted as schema keywords. The existing behavior of preserving a property named title (while still stripping the title keyword inside its sub-schema) is unchanged and remains covered by test_remove_title_from_schema_do_not_remove_title_property.

Also added a release note under releasenotes/notes/.

How did you test it?

  • Added test_remove_title_from_schema_property_named_properties (unit test for the helper) and test_from_function_with_parameter_named_properties (end-to-end create_tool_from_function test). Both fail on main with the AttributeError above and pass with the fix.
  • Ran the full tools unit-test suite locally: pytest test/tools/ -m "not integration"269 passed, 11 deselected.
  • ruff check / ruff format --check and mypy haystack/tools/from_function.py pass on the changed files.

Notes for the reviewer

  • Open PR feat: derive Tool description and parameters from function #12023 refactors from_function.py but only moves the _remove_title_from_schema(schema) call site; it does not touch the helper, so this fix is orthogonal (trivial rebase either way).
  • This PR was fully generated with an AI assistant. I have reviewed the changes and run the relevant tests.

Checklist

  • I have read the contributors guidelines and the code of conduct.
  • I have updated the related issue with new insights and changes.
  • I have added unit tests and updated the docstrings.
  • I've used one of the conventional commit types for my PR title: fix:, feat:, build:, chore:, ci:, docs:, style:, refactor:, perf:, test: and added ! in case the PR includes breaking changes.
  • I have documented my code.
  • I have added a release note file, following the contributors guidelines.
  • I have run pre-commit hooks and fixed any issue.

…ords in _remove_title_from_schema

Creating a Tool from a function or component with a parameter named
'properties' crashed with AttributeError: 'str' object has no attribute
'items'. The keys of a JSON schema 'properties' mapping are property
names, so _remove_title_from_schema now always recurses only into the
dict sub-schemas of that mapping instead of conditionally guarding just
the name 'title'.
@sohumt123
sohumt123 requested a review from a team as a code owner July 17, 2026 06:25
@sohumt123
sohumt123 requested review from sjrl and removed request for a team July 17, 2026 06:25
@vercel

vercel Bot commented Jul 17, 2026

Copy link
Copy Markdown

@sohumt123 is attempting to deploy a commit to the deepset Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant

CLAassistant commented Jul 17, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@HaystackBot

Copy link
Copy Markdown
Contributor

Hi @sohumt123, thanks a lot for your contribution! 🙏

We noticed that the Contributor License Agreement (CLA) check (license/cla) hasn't passed yet, so we've temporarily moved this PR to draft and paused the review assignment.

To get your PR reviewed, please sign the CLA via the link in the license/cla check below (or in the CLA bot comment). As soon as the check turns green, this PR will automatically be marked ready for review again and a reviewer will be re-assigned.

@HaystackBot
HaystackBot removed the request for review from sjrl July 17, 2026 08:00
@HaystackBot HaystackBot added the cla-pending PR is in draft until the contributor signs the CLA label Jul 17, 2026
@HaystackBot
HaystackBot marked this pull request as draft July 17, 2026 08:00
@sohumt123
sohumt123 marked this pull request as ready for review July 17, 2026 16:26
@sjrl
sjrl self-requested a review July 20, 2026 06:31
@sjrl sjrl self-assigned this Jul 20, 2026
@github-actions github-actions Bot added the type:documentation Improvements on the docs label Jul 20, 2026
Release notes render as reStructuredText, so inline code must use double
backticks; convert the single-backtick spans accordingly.
@github-actions

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  haystack/tools
  from_function.py
Project Total  

This report was generated by python-coverage-comment-action

@sjrl sjrl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks!

@sjrl
sjrl merged commit 3780936 into deepset-ai:main Jul 20, 2026
22 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-pending PR is in draft until the contributor signs the CLA topic:tests type:documentation Improvements on the docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants