#40348·langchain

QAWithSourcesChain removes docs from caller-provided inputs

Author: Iris070119Created Sep 10, 2026Updated Sep 17, 2026
Labelsbuglangchain-classicexternal

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)

python
import asyncio
from copy import deepcopy
from types import SimpleNamespace

from langchain_core.documents import Document
from langchain_classic.chains.qa_with_sources.base import QAWithSourcesChain


chain = SimpleNamespace(input_docs_key="docs")

sync_inputs = {
    "question": "question",
    "docs": [Document(page_content="context")],
}
sync_original = deepcopy(sync_inputs)
QAWithSourcesChain._get_docs(chain, sync_inputs, run_manager=None)
print("sync before:", sync_original)
print("sync after: ", sync_inputs)
assert sync_inputs == sync_original, (sync_original, sync_inputs)


async def reproduce_async() -> None:
    async_inputs = {
        "question": "question",
        "docs": [Document(page_content="context")],
    }
    async_original = deepcopy(async_inputs)
    await QAWithSourcesChain._aget_docs(chain, async_inputs, run_manager=None)
    print("async before:", async_original)
    print("async after: ", async_inputs)
    assert async_inputs == async_original, (async_original, async_inputs)


asyncio.run(reproduce_async())

Error Message and Stack Trace (if applicable)

bash

Description

QAWithSourcesChain removes the docs entry from caller-provided inputs. Both _get_docs and _aget_docs use pop, so the behavior affects synchronous and asynchronous execution. Applications that retain the invocation input for logging, retrying, or later processing observe an incomplete dictionary after the chain runs.

I expect reading the documents for chain execution to leave the caller-owned mapping unchanged. Both paths can read inputs[self.input_docs_key] without changing the returned documents or chain output.

System Info

System Information

OS: Windows OS Version: 10.0.26200 Python Version: 3.12.13 (main, Jul 18 2026, 17:08:38) [MSC v.1944 64 bit (AMD64)]

Package Information

langchain_core: 1.6.2 langsmith: 0.11.1 langchain_classic: 1.0.8 langchain_openai: 1.6.1 langchain_protocol: 0.0.17 langchain_tests: 1.1.9 langchain_text_splitters: 1.1.2

Optional packages not installed

deepagents deepagents-cli

Other Dependencies

anyio: 4.11.0 certifi: 2025.8.3 distro: 1.9.0 httpx: 0.28.1 jsonpatch: 1.33 numpy: 2.2.6 openai: 2.45.0 orjson: 3.11.6 packaging: 26.3 pydantic: 2.12.5 pytest: 9.1.1 pytest-asyncio: 1.4.0 pytest-benchmark: 5.1.0 pytest-codspeed: 4.0.0 pytest-recording: 0.13.4 pytest-socket: 0.8.1 pyyaml: 6.0.3 requests: 2.34.2 requests-toolbelt: 1.0.0 rich: 14.1.0 sniffio: 1.3.1 sqlalchemy: 2.0.52 syrupy: 5.5.3 tenacity: 9.1.2 tiktoken: 0.12.0 typing-extensions: 4.15.0 uuid-utils: 0.12.0 vcrpy: 8.3.0 websockets: 15.0.1 wrapt: 2.3.0 xxhash: 3.6.0 zstandard: 0.25.0

Source commit: 22f3421aeedec55962f712a34d86d9683bf6cf59

Social handles (optional)

No response