rohitg00/ai-engineering-from-scratch · error · ProtocolViolation

legacy probe did not prove the configured legacy era

Error message

legacy probe did not prove the configured legacy era

What it means

Raised by select_era when the fallback policy would downgrade to the legacy era, but the probe observation's kind is not one of the four outcomes that constitute safe evidence of a legacy server (empty, timeout, connection_closed, unrecognized). Any other outcome (e.g. a malformed error or unexpected payload) proves nothing about the configured legacy era, so the classifier refuses to guess.

Solutions

  1. Inspect the captured observation kind and match it against the safe-evidence set {empty, timeout, connection_closed, unrecognized}
  2. Fix the server or test fixture so the probe produces one of the recognized legacy-evidence outcomes
  3. Switch policy to strict if the deployment should hard-fail instead of falling back
  4. Re-run the modern discovery probe; a well-formed jsonrpc_error with a modern error code classifies as modern and never reaches this guard
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/code/main.py:351 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26). Data as JSON: /api/errors/af5470ce7ac100cd. Report an issue: GitHub.

Appendix: source

Thrown at phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/code/main.py:351

        raise ValueError("policy must be strict or fallback")
    kind = observation.get("kind")
    if kind == "discover_success":
        return "modern"
    if kind == "jsonrpc_error" and observation.get("code") in MODERN_ERROR_CODES:
        return "modern"
    if policy == "strict":
        raise ProtocolViolation("modern support was not proven; strict policy forbids fallback")
    if kind not in {"empty", "timeout", "connection_closed", "unrecognized"}:
        raise ProtocolViolation("probe outcome is not safe evidence for fallback")
    if not legacy_allowed:
        raise ProtocolViolation("legacy fallback is not allowlisted for this endpoint")
    if not isinstance(legacy_evidence, dict):
        raise ProtocolViolation("inconclusive modern probe is not positive legacy evidence")
    if (
        legacy_evidence.get("kind") != "initialize_success"
        or legacy_evidence.get("protocolVersion") != LEGACY_VERSION
    ):
        raise ProtocolViolation("legacy probe did not prove the configured legacy era")
    return "legacy"


def notification_http_outcome(request: dict[str, Any]) -> tuple[int, None]:
    if "id" in request:
        raise ValueError("request has an id and is not a notification")
    return 202, None


@dataclass(frozen=True)
class Transcript:
    name: str
    era: str
    headers: dict[str, str]
    request: dict[str, Any]
    response_status: int
    response_body: dict[str, Any] | None
    capabilities: frozenset[str] = frozenset()

View on GitHub (pinned to 39ea8a1c6d)