Skip to content

bug(core): cache implementing __len__ makes generate/agenerate raise KeyError #38440

Description

@AliMuhammadAslam

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 response

Reproduction Steps / Example Code (Python)

import asyncio

from langchain_core.caches import RETURN_VAL_TYPE, BaseCache
from langchain_core.language_models import FakeListLLM


class SizedCache(BaseCache):
    """A cache that reports its entry count via __len__ (a common pattern)."""

    def __init__(self) -> None:
        self._cache: dict[tuple[str, str], RETURN_VAL_TYPE] = {}

    def lookup(self, prompt, llm_string):
        return self._cache.get((prompt, llm_string))

    def update(self, prompt, llm_string, return_val):
        self._cache[prompt, llm_string] = return_val

    def clear(self, **kwargs):
        self._cache = {}

    def __len__(self) -> int:
        return len(self._cache)


# Empty cache -> len() == 0 -> falsy
llm = FakeListLLM(cache=SizedCache(), responses=["foo", "bar"])

# Both of these raise KeyError: 0
llm.generate(["hello"])
asyncio.run(llm.agenerate(["hello"]))

Error Message and Stack Trace (if applicable)

Traceback (most recent call last):
  File "repro.py", line 31, in <module>
    llm.generate(["hello"])
  File ".../langchain_core/language_models/llms.py", line 1070, in generate
    generations = [existing_prompts[i] for i in range(len(prompts))]
  File ".../langchain_core/language_models/llms.py", line 1070, in <listcomp>
    generations = [existing_prompts[i] for i in range(len(prompts))]
KeyError: 0

Description

The cache lookup/update helpers in langchain_core.language_models.llms decide whether a cache is configured using a truthiness check rather than an identity check:

  • get_prompts (sync lookup): if llm_cache:
  • aget_prompts (async lookup): if llm_cache:
  • aupdate_cache (async write): if llm_cache:

(update_cache, the sync write, already correctly uses if llm_cache is not None:.)

In get_prompts / aget_prompts that check guards the entire lookup loop body. For a BaseCache that implements __len__ (which many real caches do, to report their entry count), an empty cache is falsy, so the loop body is skipped. The prompt is then added to neither existing_prompts nor missing_prompts — it simply disappears. Generation is skipped because there are no missing prompts, and the final generations = [existing_prompts[i] for i in range(len(prompts))] raises KeyError.

This happens on both generate and agenerate, so caching is effectively unusable (it hard-crashes) for any cache that implements __len__ and starts empty.

I expect: an empty-but-present cache should be treated as present, exactly like the non-empty case — the call should run normally and populate the cache.
Instead: KeyError: 0.

The fix is to use is not None in the three places above (matching update_cache). Happy to open a PR with a regression test if a maintainer can assign me.

System Info

langchain-core==1.4.8 (also reproduces on current main)
Python 3.10

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions