nexu-io/open-design · error · HTTPError

Request failed with no error details

Error message

Request failed with no error details

What it means

Defensive tail of the retry loop in http.request(): the loop attempts up to `retries` times, sets last_error on HTTPError / JSON / connection failures, and returns on success. If the loop exits without ever returning and without ever assigning last_error, control reaches `raise HTTPError("Request failed with no error details")`. This is an unreachable-in-practice fallback: a real failure would have populated last_error. Hitting it usually means retries <= 0 (loop body never ran), a non-OSError/non-HTTPError exception path, or a successful-looking response that failed to return.

Source

Thrown at design-templates/last30days/scripts/lib/http.py:151

        except urllib.error.URLError as e:
            log(f"URL Error: {e.reason}")
            last_error = HTTPError(f"URL Error: {e.reason}")
            if attempt < retries - 1:
                time.sleep(RETRY_DELAY * (attempt + 1))
        except json.JSONDecodeError as e:
            log(f"JSON decode error: {e}")
            last_error = HTTPError(f"Invalid JSON response: {e}")
            raise last_error
        except (OSError, TimeoutError, ConnectionResetError) as e:
            # Handle socket-level errors (connection reset, timeout, etc.)
            log(f"Connection error: {type(e).__name__}: {e}")
            last_error = HTTPError(f"Connection error: {type(e).__name__}: {e}")
            if attempt < retries - 1:
                time.sleep(RETRY_DELAY * (attempt + 1))

    if last_error:
        raise last_error
    raise HTTPError("Request failed with no error details")


def get(url: str, headers: Optional[Dict[str, str]] = None, **kwargs) -> Dict[str, Any]:
    """Make a GET request."""
    return request("GET", url, headers=headers, **kwargs)


def post(url: str, json_data: Dict[str, Any], headers: Optional[Dict[str, str]] = None, **kwargs) -> Dict[str, Any]:
    """Make a POST request with JSON body."""
    return request("POST", url, headers=headers, json_data=json_data, **kwargs)


def post_raw(url: str, json_data: Dict[str, Any], headers: Optional[Dict[str, str]] = None, **kwargs) -> str:
    """Make a POST request with JSON body and return raw text."""
    return request("POST", url, headers=headers, json_data=json_data, raw=True, **kwargs)


def scrapecreators_headers(token: str) -> Dict[str, str]:

View on GitHub (pinned to 5be4028344)

Solutions

  1. Pass retries >= 1 so the loop body runs at least once (a real failure then populates last_error with a useful message).
  2. When catching HTTPError, also log `last_error` / the response status so the no-details fallback is never the only signal.
  3. If you control the transport, ensure it either returns a parsed dict or raises HTTPError/OSError — never returns None.
  4. Audit the except clauses if a new exception type appears (e.g. ssl.SSLError) and add it to the handlers so last_error is set.

Example fix

# before
resp = http.request("GET", url, retries=0)
# after
resp = http.request("GET", url, retries=3)
Defensive patterns

Strategy: validation

Validate before calling

if retries < 1:
    raise ValueError(f'retries must be >= 1 (got {retries}); the loop must run at least once')

Try / catch

from lib.http import HTTPError
try:
    data = http.request('GET', url, retries=3)
except HTTPError as e:
    if str(e) == 'Request failed with no error details':
        # defensive fallback hit; surface transport state for debugging
        log('http.request exhausted retries without a captured cause')
    raise

Prevention

When it happens

Trigger: Calling request() with retries <= 0 such that the for-loop body never executes; an upstream code path that swallowed the exception before last_error was set; a future refactor that adds a return-free success branch.

Common situations: A caller passing retries=0 (or negative) expecting at least one attempt; monkeypatched/mocked transport that returns None instead of raising; a Python version/stdlib change introducing a new exception type not caught by the existing handlers.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/aec1a6b3828812d0. Report an issue: GitHub.