Skip to content

fix: guard_sync raises GuardError instead of TimeoutError#41

Merged
beonde merged 3 commits into
mainfrom
fix/dx-audit-guard-sync
May 21, 2026
Merged

fix: guard_sync raises GuardError instead of TimeoutError#41
beonde merged 3 commits into
mainfrom
fix/dx-audit-guard-sync

Conversation

@beonde
Copy link
Copy Markdown
Member

@beonde beonde commented May 21, 2026

DX Audit Fix

Found during a hands-on DX walkthrough of the getting-started docs with real API calls.

Changes

guard_sync raises GuardError instead of TimeoutError (Bug #5)

When guard_sync was called outside an MCP request context (or the gRPC server wasn't responding), future.result(timeout=30.0) raised a raw TimeoutError. This is inconsistent with the async @guard decorator which raises GuardError.

Fix: Wrap the future.result() call in a try/except that catches TimeoutError and concurrent.futures.TimeoutError, re-raising as GuardError(reason=DenyReason.INTERNAL_ERROR) with a descriptive message.

Breaking Changes

Technically changes the exception type from TimeoutError to GuardError. However, GuardError is the documented and expected error type — the async @guard already raises it. Any code catching TimeoutError was relying on undocumented bug behavior.

Testing

  • @guard_sync(min_trust_level=2) called outside MCP context raises GuardError(reason=BADGE_MISSING)
  • No longer leaks TimeoutError to callers ✅

…sage

TimeoutError from concurrent.futures was leaking to users when guard_sync
was called outside MCP context. Now catches it and raises GuardError with
a helpful message explaining the likely cause.
Copilot AI review requested due to automatic review settings May 21, 2026 16:38
@github-actions
Copy link
Copy Markdown

✅ Integration tests passed! capiscio-core gRPC tests working.

@github-actions
Copy link
Copy Markdown

✅ Integration tests passed! capiscio-core gRPC tests working.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR standardizes guard_sync error behavior to match the async @guard decorator by converting timeouts from future.result(timeout=30.0) into a GuardError with DenyReason.INTERNAL_ERROR, improving consistency for callers of the public API.

Changes:

  • Wraps asyncio.run_coroutine_threadsafe(...).result(timeout=30.0) in a timeout handler.
  • Re-raises timeouts as GuardError(reason=INTERNAL_ERROR) with a descriptive detail message.
Comments suppressed due to low confidence (1)

capiscio_mcp/guard.py:701

  • This change alters the public failure mode of guard_sync (mapping a timeout into GuardError). There’s existing test coverage for guard_sync, but no test asserting that a timeout is converted into GuardError(reason=INTERNAL_ERROR) with the expected detail. Adding a targeted unit test would prevent regressions and confirm the intended behavior.
                try:
                    result = future.result(timeout=30.0)
                except (TimeoutError, concurrent.futures.TimeoutError):
                    raise GuardError(
                        reason=DenyReason.INTERNAL_ERROR,
                        detail=(
                            "Guard evaluation timed out. This usually means the "
                            "guard is being called outside of an MCP request context "
                            "or the gRPC core server is not responding."
                        ),
                    )

Comment thread capiscio_mcp/guard.py
Comment thread capiscio_mcp/guard.py
@github-actions
Copy link
Copy Markdown

✅ Integration tests passed! capiscio-core gRPC tests working.

@beonde beonde merged commit 4593117 into main May 21, 2026
10 checks passed
@beonde beonde deleted the fix/dx-audit-guard-sync branch May 21, 2026 16:53
@beonde beonde restored the fix/dx-audit-guard-sync branch May 22, 2026 02:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants