JuliusBrussee/caveman · error · MiddlewareError
invalid_plan
invalid_plan
Error message
invalid_plan
What it means
MiddlewareError raised by plan() when the returned optimization plan is internally inconsistent: duplicate segments, token accounting that doesn't add up (tokens_before - tokens_after != reduction, unique_tokens_reduced mismatch), replacements present without status "optimized" or with reduction at/below recovery_overhead_tokens, or status "optimized" with no replacements. It also fires on any KeyError/TypeError/ValueError/UnicodeError while checking the plan's shape against the request and input digest.
Solutions
- Regenerate the plan: re-run the optimize request so middleware recomputes consistent token counts
- Verify middleware and SDK versions match; upgrade the side that is behind
- Don't hand-edit plan fields; if a test fixture is involved, recompute tokens_before/tokens_after/reduction so the arithmetic holds
- Pre-check status/replacements consistency before passing the plan onward
Example fix
# before
plan_doc["status"] = "optimized" # replacements left empty
// after
if replacements:
plan_doc["status"] = "optimized"
else:
plan_doc["status"] = "skipped" Defensive patterns
Strategy: validation
Validate before calling
def plan_arithmatic_ok(p) -> bool:
m = p["metrics"]
reduction = m["tokens_before"] - m["tokens_after"]
return not (p.get("replacements") and (p["status"] != "optimized" or reduction <= m["recovery_overhead_tokens"])) \
and not (p["status"] == "optimized" and not p.get("replacements")) Type guard
def is_consistent_plan(p) -> bool:
m = p.get("metrics", {})
return m.get("tokens_before", 0) - m.get("tokens_after", 0) == m.get("reduction", 0) Try / catch
try:
checked = validate.plan(plan_doc, request, input_digest, caps)
except MiddlewareError as e:
if e.args[0] == "invalid_plan":
plan_doc = client.optimize(request) # regenerate
else:
raise Prevention
- Never hand-edit plan fields; always regenerate from the middleware
- Keep plan/request_id and input_digest immutable through any serialization round-trip
- Recompute fixture numbers when building tests so arithmetic invariants hold
- Upgrade SDK/middleware together when plan field semantics change
When it happens
Trigger: Calling the flow that validates a plan with: a plan whose request_id/input_digest don't match the original request, tampered or recomputed token counts, a plan claiming "optimized" with an empty replacements list, or a corrupted/deserialized plan object.
Common situations: A buggy or malicious middleware returning a fabricated plan; plans round-tripped through JSON edits; version skew changing field semantics; manually constructing a plan in tests with inconsistent numbers.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- invalid_plan
- invalid_recovery
- artifact_id is required
- ASGI context resolver or request bounds are invalid
- assemble requires model and session_id
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/aa16bebd7e6f2c79.
Report an issue: GitHub.
Appendix: source
Thrown at packages/sdk/python/caveman_cloud/middleware/validate.py:104
or not recovery["available"] or not recovery["persistent"] or re.fullmatch(r"cmw_[a-f0-9]{48}", r["recovery_handle"]) is None
or not r["text"].startswith(f"[caveman: shortened; exact original via caveman_retrieve handle={r['recovery_handle']}]\n")):
raise ValueError()
seen.add(r["segment_id"])
reduction += r["tokens_before"] - r["tokens_after"]
if r["unique_original"]:
unique += r["tokens_before"] - r["tokens_after"]
credited.add(r["original_sha256"])
for skipped in p["skipped"]:
if skipped["segment_id"] not in segments or skipped["segment_id"] in seen or not token(skipped["reason"]):
raise ValueError()
seen.add(skipped["segment_id"])
if (len(seen) != len(segments) or m["tokens_before"] - m["tokens_after"] != reduction or m["unique_tokens_reduced"] != unique
or (p["replacements"] and (p["status"] != "optimized" or reduction <= m["recovery_overhead_tokens"]))
or (p["status"] == "optimized" and not p["replacements"])):
raise ValueError()
return p
except (KeyError, TypeError, ValueError, UnicodeError):
raise MiddlewareError("invalid_plan") from None
def page(value: Any, args: dict, max_bytes: int) -> dict:
try:
p = value
if (type(p["schema_version"]) is not int or p["schema_version"] != 1 or p["handle"] != args["handle"] or not token(p["source_id"]) or not digest(p["original_sha256"])
or not isinstance(p["text"], str) or not integer(p["total_bytes"]) or not integer(p["offset"]) or p["offset"] != args.get("offset", 0)
or p["kind"] not in ("original_page", "excerpt") or type(p["complete"]) is not bool
or not (p["next_offset"] is None or integer(p["next_offset"]))):
raise ValueError()
length = len(p["text"].encode("utf-8"))
end = p["offset"] + length
if length > max_bytes:
raise ValueError()
if p["kind"] == "original_page" and (end > p["total_bytes"] or p["next_offset"] != (end if end < p["total_bytes"] else None)
or p["complete"] != (p["offset"] == 0 and length == p["total_bytes"])):
raise ValueError()
if p["kind"] == "excerpt" and (p["complete"] or not args.get("query") or p["next_offset"] != 0):View on GitHub (pinned to 3ee70a1026)