Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/adcp/decisioning/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ def _internal_error_details(exc: BaseException) -> dict[str, Any]:
except Exception:
# Defensive — never let a narrowing bug 500 the wire.
# The exception type still lets adopters triage via server logs.
pass
return details
return details


Expand Down
34 changes: 34 additions & 0 deletions tests/test_decisioning_dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,40 @@ async def get_products(self, req, ctx):
assert "eyJhbGciOiJIUzI1NiJ9" not in str(exc_info.value.details)


def test_internal_error_details_survive_a_narrowing_failure_without_raw_values(monkeypatch):
from pydantic import ValidationError

from adcp.decisioning.dispatch import _internal_error_details
from adcp.types import error_narrowing

class _InvalidResponse(BaseModel):
count: int

with pytest.raises(ValidationError) as captured:
_InvalidResponse.model_validate({"count": "raw-input-marker"})
observed = []

def broken_narrowing(errors):
observed.extend(errors)
yield {"msg": "partial-narrowing-marker"}
raise RuntimeError("raw-narrowing-failure-marker")

monkeypatch.setattr(error_narrowing, "narrow_union_errors", broken_narrowing)
details = _internal_error_details(captured.value)
assert observed and all("input" not in item and "ctx" not in item for item in observed)
assert details == {"caused_by": {"type": "ValidationError"}}
# A partial generator result and either raw value must not enter the error
# response; the secondary narrowing failure must not replace the original.
assert all(
marker not in str(details)
for marker in (
"raw-input-marker",
"partial-narrowing-marker",
"raw-narrowing-failure-marker",
)
)


@pytest.mark.asyncio
async def test_invoke_validation_error_surfaces_narrowed_field_paths(
executor: ThreadPoolExecutor,
Expand Down
Loading