From 911041e2a4d11b86763a9ba3b2130579b3b6d3e2 Mon Sep 17 00:00:00 2001 From: Volodymyr Kasaraba Date: Mon, 23 Feb 2026 17:10:14 -0500 Subject: [PATCH 1/3] correct 403 response processing --- packages/narada/src/narada/client.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/narada/src/narada/client.py b/packages/narada/src/narada/client.py index 695d27c..2d47625 100644 --- a/packages/narada/src/narada/client.py +++ b/packages/narada/src/narada/client.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import json import logging import os import subprocess @@ -176,6 +177,23 @@ async def open_and_initialize_cloud_browser_window( ) as resp: if not resp.ok: error_text = await resp.text() + if resp.status == 403: + try: + body = json.loads(error_text) if error_text else {} + detail = ( + body.get("detail", body) + if isinstance(body, dict) + else {} + ) + err = RuntimeError( + f"Failed to create cloud browser session: {resp.status} {error_text}\n" + f"Endpoint URL: {endpoint_url}" + ) + err.status_code = resp.status # type: ignore[attr-defined] + err.detail = detail # type: ignore[attr-defined] + raise err + except (ValueError, TypeError): + pass raise RuntimeError( f"Failed to create cloud browser session: {resp.status} {error_text}\n" f"Endpoint URL: {endpoint_url}" From 46d796ff774c6b112c327f6cc2755cdb57c58855 Mon Sep 17 00:00:00 2001 From: Volodymyr Kasaraba Date: Tue, 3 Mar 2026 14:32:50 -0500 Subject: [PATCH 2/3] improve code quality --- packages/narada/src/narada/client.py | 50 ++++++++++++++++++---------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/packages/narada/src/narada/client.py b/packages/narada/src/narada/client.py index 2d47625..56f1127 100644 --- a/packages/narada/src/narada/client.py +++ b/packages/narada/src/narada/client.py @@ -7,6 +7,7 @@ import subprocess import sys from dataclasses import dataclass +from http import HTTPStatus from typing import Any from uuid import uuid4 @@ -31,6 +32,7 @@ ) from playwright.async_api import TimeoutError as PlaywrightTimeoutError from playwright.async_api._context_manager import PlaywrightContextManager +from pydantic import BaseModel, ValidationError from rich.console import Console from narada.config import BrowserConfig, ProxyConfig @@ -50,6 +52,28 @@ class _LaunchBrowserResult: side_panel_page: Page +class ApiErrorPayload(BaseModel): + detail: Any | None = None + + @classmethod + def from_error_text(cls, error_text: str | None) -> "ApiErrorPayload": + if not error_text: + return cls() + + try: + return cls.model_validate_json(error_text) + except ValidationError: + try: + body = json.loads(error_text) + except (ValueError, TypeError): + return cls() + + if isinstance(body, dict): + return cls(detail=body.get("detail", body)) + + return cls() + + class Narada: _BROWSER_WINDOW_ID_SELECTOR = "#narada-browser-window-id" _UNSUPPORTED_BROWSER_INDICATOR_SELECTOR = "#narada-unsupported-browser" @@ -177,23 +201,15 @@ async def open_and_initialize_cloud_browser_window( ) as resp: if not resp.ok: error_text = await resp.text() - if resp.status == 403: - try: - body = json.loads(error_text) if error_text else {} - detail = ( - body.get("detail", body) - if isinstance(body, dict) - else {} - ) - err = RuntimeError( - f"Failed to create cloud browser session: {resp.status} {error_text}\n" - f"Endpoint URL: {endpoint_url}" - ) - err.status_code = resp.status # type: ignore[attr-defined] - err.detail = detail # type: ignore[attr-defined] - raise err - except (ValueError, TypeError): - pass + if resp.status == HTTPStatus.FORBIDDEN: + error = ApiErrorPayload.from_error_text(error_text) + err = RuntimeError( + f"Failed to create cloud browser session: {resp.status} {error_text}\n" + f"Endpoint URL: {endpoint_url}" + ) + err.status_code = resp.status # type: ignore[attr-defined] + err.detail = error.detail # type: ignore[attr-defined] + raise err raise RuntimeError( f"Failed to create cloud browser session: {resp.status} {error_text}\n" f"Endpoint URL: {endpoint_url}" From 87db542ffa0013975708005b626f1b4cacd1bbf8 Mon Sep 17 00:00:00 2001 From: Volodymyr Kasaraba Date: Tue, 3 Mar 2026 15:38:42 -0500 Subject: [PATCH 3/3] improve code quality --- packages/narada/src/narada/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/narada/src/narada/client.py b/packages/narada/src/narada/client.py index 56f1127..0298fd2 100644 --- a/packages/narada/src/narada/client.py +++ b/packages/narada/src/narada/client.py @@ -56,7 +56,7 @@ class ApiErrorPayload(BaseModel): detail: Any | None = None @classmethod - def from_error_text(cls, error_text: str | None) -> "ApiErrorPayload": + def from_error_text(cls, error_text: str | None) -> ApiErrorPayload: if not error_text: return cls()