Skip to content
Open
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
12 changes: 6 additions & 6 deletions freerelay/control_plane/learner/outcome_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ async def ensure_group(self) -> None:
logger.info(
"consumer_group_created stream=%s group=%s", self._stream, self._group
)
except Exception as exc:
except redis.asyncio.ResponseError as exc:
# BUSYGROUP means the group already exists — that's fine
if "BUSYGROUP" in str(exc):
logger.debug(
Expand Down Expand Up @@ -167,7 +167,7 @@ async def consume_batch(
count=batch_size,
block=block_ms,
)
except Exception:
except redis.asyncio.ResponseError:
logger.exception("consume_batch_read_error")
return []

Expand All @@ -177,7 +177,7 @@ async def consume_batch(
try:
record = OutcomeRecord.from_stream(msg_id, fields)
records.append(record)
except Exception:
except (json.JSONDecodeError, ValueError, TypeError):
logger.exception("consume_batch_parse_error id=%s", msg_id)

if records:
Expand All @@ -195,7 +195,7 @@ async def acknowledge(self, message_ids: list[str]) -> int:
count = await self._redis.xack(self._stream, self._group, *message_ids)
logger.debug("acked_outcomes count=%d", count)
return count
except Exception:
except redis.asyncio.ResponseError:
logger.exception("acknowledge_error")
return 0

Expand Down Expand Up @@ -224,7 +224,7 @@ async def pending_info(self) -> dict[str, Any]:
"max_id": info.get("max"),
"consumers": info.get("consumers", []),
}
except Exception:
except redis.asyncio.ResponseError:
logger.exception("pending_info_error")
return {"pending_count": 0}

Expand Down Expand Up @@ -274,6 +274,6 @@ async def claim_stale(
logger.info("claimed_stale_outcomes count=%d", len(records))
return records

except Exception:
except redis.asyncio.ResponseError:
logger.exception("claim_stale_error")
return []
16 changes: 8 additions & 8 deletions freerelay/control_plane/learner/policy_publisher.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ async def publish(
)
return version

except Exception:
except redis.asyncio.ResponseError:
logger.exception("policy_publish_error")
raise

Expand All @@ -96,7 +96,7 @@ async def load_current(self) -> dict[str, Any] | None:
if raw is None:
return None
return json.loads(raw)
except (json.JSONDecodeError, Exception):
except (json.JSONDecodeError, redis.asyncio.ResponseError):
logger.exception("policy_load_error")
return None

Expand All @@ -105,7 +105,7 @@ async def get_version_history(self, count: int = 10) -> list[dict[str, Any]]:
try:
entries = await self._redis.lrange(POLICY_HISTORY_KEY, 0, count - 1)
return [json.loads(e) for e in entries]
except Exception:
except redis.asyncio.ResponseError:
logger.exception("policy_history_error")
return []

Expand All @@ -127,7 +127,7 @@ async def rollback(self, target_version: str) -> bool:
logger.info("policy_rollback version=%s", target_version)
return True

except Exception:
except redis.asyncio.ResponseError:
logger.exception("rollback_error")
return False

Expand All @@ -143,7 +143,7 @@ async def snapshot_version(self, version: str) -> None:
versioned_key = f"freerelay:policy:versions:{version}"
await self._redis.set(versioned_key, raw, ex=86400 * 7) # 7 day TTL
logger.debug("policy_version_snapshot version=%s", version)
except Exception:
except redis.asyncio.ResponseError:
logger.exception("snapshot_version_error")

async def subscribe_to_updates(self, callback: Any) -> None:
Expand All @@ -162,9 +162,9 @@ async def subscribe_to_updates(self, callback: Any) -> None:
try:
policy = json.loads(message["data"])
await callback(policy)
except Exception:
except (json.JSONDecodeError, ValueError, TypeError):
logger.exception("policy_callback_error")
except Exception:
except redis.asyncio.ResponseError:
logger.exception("policy_subscribe_error")
finally:
await pubsub.unsubscribe(POLICY_CHANNEL)
Expand All @@ -177,6 +177,6 @@ async def delete_policy(self) -> bool:
if deleted:
logger.info("policy_deleted")
return bool(deleted)
except Exception:
except redis.asyncio.ResponseError:
logger.exception("policy_delete_error")
return False
2 changes: 1 addition & 1 deletion freerelay/core/execution/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ async def execute_hedged(
for _name, circuit in circuits.items():
await circuit.record_success()
return response
except Exception as e:
except (ProviderError, ValueError, TypeError) as e:
# Record failure on all involved circuit breakers
for _name, circuit in circuits.items():
status = e.status_code if isinstance(e, ProviderError) else None
Expand Down
6 changes: 3 additions & 3 deletions freerelay/core/intelligence/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def lookup(self, request: ChatCompletionRequest) -> ChatCompletionResponse | Non
if entry and (time.time() - entry.created_at) < entry.ttl:
try:
return ChatCompletionResponse.model_validate_json(entry.response_json)
except Exception:
except (ValueError, TypeError):
del self._entries[key]
return None

Expand All @@ -153,9 +153,9 @@ def lookup(self, request: ChatCompletionRequest) -> ChatCompletionResponse | Non
return ChatCompletionResponse.model_validate_json(
candidate.response_json
)
except Exception:
except (ValueError, TypeError):
continue
except Exception:
except (TypeError, ValueError, KeyError):
pass

return None
Expand Down
2 changes: 1 addition & 1 deletion freerelay/core/observability/supabase_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ def log(self, record: OutcomeRecord) -> None:
"schema_pass": record.schema_pass,
"notes": record.notes
}).execute()
except Exception as e:
except (OSError, ValueError, TypeError) as e:
logger.error(f"Failed to log usage to Supabase: {e}")
2 changes: 1 addition & 1 deletion freerelay/core/routing/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def _load_capability_matrix(self, settings: Settings) -> CapabilityMatrix | None
matrix = CapabilityMatrix.model_validate(data)
logger.info("Loaded capability matrix: %d models", len(matrix.models))
return matrix
except Exception:
except (OSError, yaml.YAMLError, ValueError):
logger.exception("Failed to load capability matrix: %s", path)
return None

Expand Down
2 changes: 1 addition & 1 deletion freerelay/core/routing/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def _eval_condition_context(condition: str, context: dict[str, Any]) -> bool:
return False
try:
return bool(eval(condition, {"__builtins__": {}}, context))
except Exception:
except (SyntaxError, NameError, TypeError, ValueError):
logger.warning("Failed to evaluate condition: %s", condition)
return False

Expand Down
4 changes: 2 additions & 2 deletions freerelay/dashboard/ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async def broadcast(self, data: dict[str, object]) -> None:
for client in self._clients:
try:
await client.send_text(message)
except Exception:
except (RuntimeError, ConnectionResetError):
disconnected.append(client)

for client in disconnected:
Expand Down Expand Up @@ -75,7 +75,7 @@ async def start_broadcasting(self, get_metrics: Any) -> None:
"data": metrics,
}
)
except Exception as e:
except (RuntimeError, ValueError) as e:
logger.error("Metrics broadcast error: %s", e)

await asyncio.sleep(self.interval)
Expand Down
7 changes: 5 additions & 2 deletions freerelay/data_plane/execution/cancellation.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from enum import StrEnum
from typing import Any

import httpx

logger = logging.getLogger("freerelay.data_plane.cancellation")


Expand Down Expand Up @@ -112,10 +114,11 @@ async def cancel(
if self._httpx_request is not None and self._httpx_client is not None:
try:
await self._httpx_client.cancel_request(self._httpx_request)
except Exception:
except (OSError, httpx.RequestError) as err:
logger.debug(
"Failed to cancel httpx request %s",
"Failed to cancel httpx request %s: %s",
self._state.request_id,
err,
)

# Cancel timeout task
Expand Down
4 changes: 3 additions & 1 deletion freerelay/data_plane/ingress/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING

import redis.asyncio

if TYPE_CHECKING:
from redis.asyncio import Redis

Expand Down Expand Up @@ -101,7 +103,7 @@ async def _lookup_redis(self, key_hash: str) -> str | None:
result.decode("utf-8") if isinstance(result, bytes) else str(result)
)
return None
except Exception:
except redis.asyncio.RedisError as err:
logger.exception("Redis key lookup failed for hash %s", key_hash[:8])
return None

Expand Down
6 changes: 4 additions & 2 deletions freerelay/data_plane/ingress/idempotency.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any

import redis.asyncio

if TYPE_CHECKING:
from redis.asyncio import Redis

Expand Down Expand Up @@ -69,7 +71,7 @@ async def check(self, request_id: str) -> dict[str, Any] | None:
if self._redis is not None:
try:
return await self._check_redis(request_id)
except Exception:
except redis.asyncio.RedisError:
logger.exception("Redis idempotency check failed, using fallback")
return self._check_memory(request_id)

Expand Down Expand Up @@ -123,7 +125,7 @@ async def store(self, request_id: str, response: dict[str, Any]) -> bool:
if self._redis is not None:
try:
return await self._store_redis(request_id, data)
except Exception:
except redis.asyncio.RedisError:
logger.exception("Redis idempotency store failed, using fallback")
return self._store_memory(request_id, data)

Expand Down
4 changes: 3 additions & 1 deletion freerelay/data_plane/ingress/rate_limit.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING

import redis.asyncio

if TYPE_CHECKING:
from redis.asyncio import Redis

Expand Down Expand Up @@ -138,7 +140,7 @@ async def check_rate_limit(
if self._redis is not None:
try:
return await self._check_redis(namespace, limit)
except Exception:
except redis.asyncio.RedisError:
logger.exception("Redis rate limit check failed, using fallback")
return self._fallback.check(namespace, limit, self._window)

Expand Down
6 changes: 3 additions & 3 deletions freerelay/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def create_app() -> FastAPI:
from fastapi.responses import ORJSONResponse

default_response_class: type[Response] = ORJSONResponse
except Exception:
except ImportError:
default_response_class = JSONResponse

app = FastAPI(
Expand Down Expand Up @@ -202,15 +202,15 @@ async def chat_completions(request: Request) -> Response:

try:
body = await request.body()
except Exception:
except OSError:
return JSONResponse(
status_code=400,
content=ChatCompletionResponse.error_body("Invalid JSON body", 400),
)

try:
req = ChatCompletionRequest.model_validate_json(body)
except Exception as e:
except (ValueError, TypeError) as e:
return JSONResponse(
status_code=400,
content=ChatCompletionResponse.error_body(f"Invalid request: {e}", 400),
Expand Down
2 changes: 1 addition & 1 deletion freerelay/middleware/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def _verify_token_supabase(token_hash: str) -> dict[str, str] | None:
_AUTH_CACHE[token_hash] = (user_info, now + _CACHE_TTL)
return user_info
return None
except Exception as e:
except (OSError, KeyError, TypeError, IndexError) as e:
logger.error(f"Supabase auth error: {e}")
return None

Expand Down
2 changes: 1 addition & 1 deletion freerelay/middleware/idempotency.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ async def dispatch(
if len(self._cache) >= _MAX_CACHE_SIZE:
self._cache.popitem(last=False)
self._cache[idempotency_key] = (time.time(), body, response.status_code)
except Exception:
except (ValueError, TypeError):
pass

return response
2 changes: 1 addition & 1 deletion freerelay/providers/codex.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def get_codex_token_status() -> dict[str, object]:
else "Token expired. Re-authenticate with 'openclaw configure'."
),
}
except Exception:
except (TypeError, ValueError):
pass

return {
Expand Down
6 changes: 5 additions & 1 deletion freerelay/providers/opencode.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ async def fetch_opencode_models(api_key: str = "") -> list[dict[str, str]]:
}
)
return models
except Exception:
except httpx.RequestError:
pass
except (ValueError, TypeError):
pass
except AttributeError:
pass

# Fallback: return known free model
Expand Down
4 changes: 2 additions & 2 deletions freerelay/shared/security/crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def decrypt_key(ciphertext: str, secret: bytes) -> str:

try:
bundle = base64.b64decode(ciphertext)
except Exception as exc:
except (ValueError, TypeError) as exc:
raise ValueError("Invalid base64 ciphertext") from exc

if len(bundle) < 28: # 12 (nonce) + 16 (tag) minimum
Expand Down Expand Up @@ -118,7 +118,7 @@ def _aes_gcm_decrypt(ciphertext: bytes, key: bytes, nonce: bytes, tag: bytes) ->
"cryptography package required for AES-256-GCM. "
"Install with: pip install cryptography"
) from e
except Exception as exc:
except ValueError as exc:
raise ValueError("Decryption failed: invalid key or corrupted data") from exc


Expand Down
6 changes: 3 additions & 3 deletions freerelay/shared/tenancy/audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ async def purge_expired(self, namespace: str) -> int:
namespace,
)
return len(ids)
except Exception as exc:
except redis.asyncio.ResponseError as exc:
logger.error("Failed to purge audit records: %s", exc)
return 0

Expand Down Expand Up @@ -252,7 +252,7 @@ async def _persist(self, namespace: str, record: AuditRecord) -> None:
maxlen=100_000, # Cap stream size
)
return
except Exception as exc:
except redis.asyncio.ResponseError as exc:
logger.error("Redis audit write failed, falling back to memory: %s", exc)

# In-memory fallback
Expand Down Expand Up @@ -289,7 +289,7 @@ async def _get_from_redis(
# Return newest first
records.reverse()
return records
except Exception as exc:
except redis.asyncio.ResponseError as exc:
logger.error("Redis audit read failed: %s", exc)
return []

Expand Down
Loading