Skip to content

bug(core): ContextThreadPoolExecutor.map rejects generator inputs #39211

Description

Submission checklist

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Package (Required)

  • langchain
  • langchain-openai
  • langchain-anthropic
  • langchain-classic
  • langchain-core
  • langchain-model-profiles
  • langchain-tests
  • langchain-text-splitters
  • langchain-chroma
  • langchain-deepseek
  • langchain-exa
  • langchain-fireworks
  • langchain-groq
  • langchain-huggingface
  • langchain-mistralai
  • langchain-nomic
  • langchain-ollama
  • langchain-openrouter
  • langchain-perplexity
  • langchain-qdrant
  • langchain-xai
  • Other / not sure / general

Related Issues / PRs

No related issues or pull requests found after searching by the class name, exception text, and ThreadPoolExecutor.map iterable behavior.

Reproduction Steps / Example Code (Python)

from concurrent.futures import ThreadPoolExecutor

from langchain_core.runnables.config import ContextThreadPoolExecutor


def values():
    yield from range(3)


with ThreadPoolExecutor(max_workers=2) as executor:
    print(list(executor.map(lambda value: value * 2, values())))
    # [0, 2, 4]

with ContextThreadPoolExecutor(max_workers=2) as executor:
    print(list(executor.map(lambda value: value * 2, values())))
    # TypeError: object of type 'generator' has no len()

Error Message and Stack Trace (if applicable)

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File ".../langchain/libs/core/langchain_core/runnables/config.py", line 647, in map
    contexts = [copy_context() for _ in range(len(iterables[0]))]  # type: ignore[arg-type]
                                              ^^^^^^^^^^^^^^^^^
TypeError: object of type 'generator' has no len()

Description

ContextThreadPoolExecutor.map() declares each input as an Iterable, matching concurrent.futures.Executor.map(), but it calls len(iterables[0]) before delegating to the standard-library implementation. Generators and other unsized iterables are therefore rejected even though they are valid inputs to Executor.map().

Expected behavior:

  • ContextThreadPoolExecutor.map() accepts generators and other iterables supported by ThreadPoolExecutor.map().
  • The mapped function still receives a copied caller context.
  • Multiple iterables retain the standard shortest-iterable behavior.

Current behavior:

  • A generator passed as the first iterable raises TypeError before any work is submitted.
  • The same generator works with ThreadPoolExecutor.map().

Root cause:

The override preallocates one context per item with range(len(iterables[0])). This assumes that the first iterable is sized and also duplicates responsibility already handled by ContextThreadPoolExecutor.submit().

Proposed implementation

I plan to make the following focused change in ContextThreadPoolExecutor.map():

def map(
    self,
    fn: Callable[..., T],
    *iterables: Iterable[Any],
    **kwargs: Any,
) -> Iterator[T]:
    return super().map(fn, *iterables, **kwargs)

This works because the standard ThreadPoolExecutor.map() implementation submits each invocation through self.submit(). Dynamic dispatch therefore reaches the existing ContextThreadPoolExecutor.submit() override, which wraps every submitted call with copy_context().run(...). Context propagation remains intact without measuring, copying, or separately consuming any input iterable.

The implementation will:

  1. Remove the len(iterables[0]) call and the eager contexts list.
  2. Remove the custom _wrapped_fn and its shared contexts.pop() mutation.
  3. Delegate directly to the superclass so generators, lazy iterables, multiple iterables, timeout, chunksize, and version-specific map keyword arguments retain standard-library semantics.
  4. Keep the existing public method signature and return type unchanged.
  5. Avoid materializing the first iterable as a list, which would otherwise change laziness and increase memory use for large or unbounded inputs.

Regression tests

I plan to add focused unit coverage for ContextThreadPoolExecutor:

  • Pass a generator as the first iterable and assert that all mapped results are returned in order.
  • Set a ContextVar in the caller and assert that mapped worker calls receive its value, proving the delegation still uses the context-copying submit() override.
  • Map across a generator and a second, shorter iterable and assert standard shortest-iterable behavior.
  • Keep the tests deterministic and network-free.

No dependency, exported symbol, or public API change is required.

I reproduced the failure against the latest master at commit dd6081977099b93eb035f81c993434ca90a018ca. I also validated this exact delegation approach locally with generator input, multiple iterables, and ContextVar propagation.

Could a maintainer please assign this issue to me? I would be happy to implement this change and its regression tests once the approach is approved.

AI-assisted investigation disclosure: I used Codex to inspect the current implementation and history, search for duplicates, run the reproduction, and validate the proposed implementation. I reviewed the evidence and implementation plan before submitting.

System Info

System Information

OS: Darwin
OS Version: Darwin Kernel Version 25.5.0: Tue Jun 9 22:27:52 PDT 2026; root:xnu-12377.121.10~1/RELEASE_ARM64_T8112
Python Version: 3.12.13 (main, Jun 23 2026, 15:44:24) [Clang 22.1.3 ]

Package Information

langchain_core: 1.5.3
langsmith: 0.8.18
langchain_protocol: 0.0.17
langchain_tests: 1.1.9

Optional packages not installed

deepagents
deepagents-cli

Other Dependencies

httpx: 0.28.1
jsonpatch: 1.33
numpy: 2.3.5
orjson: 3.11.6
packaging: 26.0
pydantic: 2.12.5
pytest: 9.0.3
pytest-asyncio: 1.3.0
pytest-benchmark: 5.2.3
pytest-codspeed: 4.3.0
pytest-recording: 0.13.4
pytest-socket: 0.7.0
pyyaml: 6.0.3
requests: 2.33.0
requests-toolbelt: 1.0.0
rich: 14.2.0
syrupy: 5.1.0
tenacity: 9.1.4
typing-extensions: 4.15.0
uuid-utils: 0.16.0
vcrpy: 8.2.1
websockets: 16.0
wrapt: 2.0.1
xxhash: 3.6.0
zstandard: 0.25.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugRelated to a bug, vulnerability, unexpected error with an existing featurecore`langchain-core` package issues & PRsexternal

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions