microsoft/autogen · error · AttributeError

The provided LangChain tool '{name}' does not have a callabl

Error message

The provided LangChain tool '{name}' does not have a callable 'func' or '_run' method.

What it means

LangChainToolAdapter.__init__ inspects the wrapped LangChain tool for a callable 'func' attribute (StructuredTool-style) or '_run' method (BaseTool subclass). If neither is present/callable, AttributeError is raised with the tool's name. This typically happens with tools whose executable is exposed differently (e.g. coroutine-only StructuredTool) or tools that are pure declaration objects.

Source

Thrown at python/packages/autogen-ext/src/autogen_ext/tools/langchain/_langchain_adapter.py:159

                asyncio.run(main())

    """

    def __init__(self, langchain_tool: LangChainTool):
        self._langchain_tool: LangChainTool = langchain_tool

        # Extract name and description
        name = self._langchain_tool.name
        description = self._langchain_tool.description or ""

        # Determine the callable method
        if hasattr(self._langchain_tool, "func") and callable(self._langchain_tool.func):  # type: ignore
            assert self._langchain_tool.func is not None  # type: ignore
            self._callable: Callable[..., Any] = self._langchain_tool.func  # type: ignore
        elif hasattr(self._langchain_tool, "_run") and callable(self._langchain_tool._run):  # type: ignore
            self._callable: Callable[..., Any] = self._langchain_tool._run  # type: ignore
        else:
            raise AttributeError(
                f"The provided LangChain tool '{name}' does not have a callable 'func' or '_run' method."
            )

        # Determine args_type
        if self._langchain_tool.args_schema:  # pyright: ignore
            args_type = self._langchain_tool.args_schema  # pyright: ignore
        else:
            # Infer args_type from the callable's signature
            sig = inspect.signature(cast(Callable[..., Any], self._callable))  # type: ignore
            fields = {
                k: (v.annotation, Field(...))
                for k, v in sig.parameters.items()
                if k != "self" and v.kind not in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD)
            }
            args_type = create_model(f"{name}Args", **fields)  # type: ignore
            # Note: type ignore is used due to a LangChain typing limitation

        # Ensure args_type is a subclass of BaseModel

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Create the tool so a callable func exists: use @tool decorator on a sync function, or StructuredTool.from_function(fn).
  2. For async functions, decorate them with @tool anyway (the decorator wraps them and provides a runnable path), rather than hand-constructing StructuredTool with only coroutine.
  3. Check the LangChain version compatibility with the autogen-ext langchain extra; upgrade/downgrade langchain to a supported major version.
  4. Verify the object really is a BaseTool instance before adapting: isinstance(tool, BaseTool).

Example fix

# before
from langchain_core.tools import StructuredTool

tool = StructuredTool(
    name="fetch",
    description="fetch data",
    coroutine=async_fetch,   # func missing -> adapter raises
)
adapter = LangChainToolAdapter(tool)

# after
from langchain_core.tools import tool as lc_tool

@lc_tool
def fetch(q: str) -> str:
    """fetch data"""
    return do_fetch(q)

adapter = LangChainToolAdapter(fetch)
Defensive patterns

Strategy: type-guard

Validate before calling

fn = getattr(tool, "func", None)
run = getattr(tool, "_run", None)
if not (callable(fn) or callable(run)):
    raise TypeError(f"tool {tool!r} exposes no callable func/_run; wrap it with @tool first")

Type guard

from typing import Any, Callable, TypeGuard

def is_adaptable_langchain_tool(tool: Any) -> TypeGuard[Any]:
    fn = getattr(tool, "func", None)
    run = getattr(tool, "_run", None)
    return callable(fn) or callable(run)

Try / catch

try:
    adapter = LangChainToolAdapter(tool)
except AttributeError as e:
    raise TypeError(f"Cannot adapt {type(tool).__name__}: {e}") from e

Prevention

When it happens

Trigger: Passing a LangChain tool to LangChainToolAdapter where tool.func is None/absent and tool._run is not callable — e.g. a StructuredTool built with only coroutine=..., since StructuredTool sets func to a placeholder raising NotImplementedError that may not be flagged callable-but-usable, or a mock/Pydantic model mistaken for a tool.

Common situations: Wrapping an async-only StructuredTool created via StructuredTool(coroutine=async_fn) in older langchain versions; passing a tool schema/dict from an agent framework rather than an actual tool instance; passing @tool-decorated object from an incompatible langchain major version where attributes moved; passing Mock objects in tests.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/4bcd146fa5808b45. Report an issue: GitHub.