Troubleshooting
Common issues and fixes when developing with ActingWeb.
401 at /mcp
Cause: No authentication configured or provided. MCP is OAuth2-protected in production.
Fix: Configure OAuth2 (Google/GitHub) with .with_oauth(…). Unauthenticated requests should return 401 with WWW-Authenticate header. For local, temporarily allow open access or sign in via /www.
DynamoDB Local connection errors
Symptom: Timeouts or table not found.
Fix: Ensure DynamoDB Local is running and set env vars:
export AWS_ACCESS_KEY_ID=local export AWS_SECRET_ACCESS_KEY=local export AWS_DEFAULT_REGION=us-east-1 export AWS_DB_HOST=http://localhost:8000
Slow first request after startup
Explanation: The permission system compiles/caches trust types on first use.
Fix: This is initialized automatically during framework integration. If you still see warmups during requests, check logs for initialization errors.
Tools/prompts don’t appear in tools/list or prompts/list
Check that you decorated hooks correctly: - Tools: @app.action_hook(“name”) + @mcp_tool(…) - Prompts: @app.method_hook(“name”) + @mcp_prompt(…)
Verify unified access control isn’t filtering them out for the current peer.
Property changes not visible in Web UI
Hook returns None for GET hides the property completely.
Hook returns None for PUT/POST marks the property read-only.
Subscription Callbacks Not Delivered
Symptom: Property changes on the publisher are not reaching subscribers.
Causes and fixes:
Circuit breaker is open: Check the circuit breaker status for the peer:
from actingweb.fanout import FanOutManager manager = FanOutManager(actor) status = manager.get_circuit_breaker_status(peer_id) if status == "OPEN": # Peer is unavailable, reset if issue resolved manager.reset_circuit_breaker(peer_id)
Peer URL unreachable: Verify the peer’s callback URL is accessible and responding.
Trust not approved: Ensure the trust relationship is approved on both sides.
Subscription target mismatch: Verify the subscription target matches what you’re publishing.
Unexpected Resync Callbacks
Symptom: Full resync callbacks triggered frequently instead of incremental diffs.
Causes and fixes:
Network latency: If callbacks arrive out-of-order often, increase the gap timeout:
app.with_subscription_processing(gap_timeout_seconds=10.0) # Default is 5.0
Burst updates: Rapid property changes can cause sequence gaps. Consider using suspension:
actor.subscriptions.suspend(target="properties") # ... perform bulk updates ... actor.subscriptions.resume(target="properties") # Sends single resync
Publisher restart: After a publisher restarts, sequence numbers reset. Subscribers should handle resync gracefully.
Duplicate Callbacks Being Processed
Symptom: Same data processed multiple times in your
@subscription_data_hook.Causes and fixes:
auto_sequence disabled: Ensure subscription processing is enabled:
app.with_subscription_processing(auto_sequence=True) # Default
Using raw callback_hook: The raw
@callback_hook("subscription")doesn’t deduplicate. Migrate to@subscription_data_hook.Multiple hook registrations: Check you haven’t registered the same hook twice.
Peer Data Not Cleaned Up After Trust Deletion
Symptom: RemotePeerStore data persists after trust relationship is deleted.
Causes and fixes:
auto_cleanup disabled: Enable automatic cleanup:
app.with_subscription_processing(auto_cleanup=True) # Default
Custom trust hook overriding: If you have a
@trust_hook("delete"), ensure it doesn’t prevent default cleanup.Manual cleanup needed: For legacy data, manually clean up:
from actingweb.remote_storage import RemotePeerStore store = RemotePeerStore(actor, peer_id) store.delete_all()
Subscriber Returning 429 (Too Many Requests)
Symptom: Publisher receives 429 responses when sending callbacks.
Causes and fixes:
Pending queue full: The subscriber’s
max_pendinglimit was exceeded:# On subscriber, increase if needed: app.with_subscription_processing(max_pending=200) # Default is 100
Processing too slow: The subscriber’s hook is blocking. Keep hooks fast or offload work.
Publisher retry strategy: Implement exponential backoff when receiving 429:
# FanOutManager handles retries automatically # For custom implementations, wait before retrying
Sequence Gaps Not Resolving
Symptom: Callbacks stuck in pending queue, never processed.
Causes and fixes:
Gap timeout too long: Reduce the timeout to trigger resync sooner:
app.with_subscription_processing(gap_timeout_seconds=3.0)
Missing callbacks: The publisher may have lost callbacks. Manually trigger resync:
# On publisher side: actor.subscriptions.resume(target="properties")
Check pending state: Use devtest endpoints to inspect pending queue (devtest mode only):
GET /{actor_id}/devtest/callback_state/{peer_id}/{subscription_id}