ZhuLinsen/daily_stock_analysis · warning · Error

Desktop backend origin is invalid

Error message

Desktop backend origin is invalid

What it means

Raised by PortfolioService.query_trades when the side filter, after strip+lowercase, is not in VALID_SIDES = {'buy','sell'} (portfolio_service.py:36). The check runs before query_trades hits the repository, so an invalid side never reaches SQL.

Source

Thrown at apps/dsa-desktop/main.js:1362

function buildDesktopShareImageUrl(pageUrl, recordId, expectedBackendOrigin = '') {
  if (!Number.isSafeInteger(recordId) || recordId <= 0) {
    throw new Error('Invalid share image record ID');
  }

  let page;
  try {
    page = new URL(pageUrl);
  } catch (_error) {
    throw new Error('Desktop backend URL is unavailable');
  }

  let expectedOrigin = page.origin;
  if (expectedBackendOrigin) {
    try {
      expectedOrigin = new URL(expectedBackendOrigin).origin;
    } catch (_error) {
      throw new Error('Desktop backend origin is invalid');
    }
  }
  if (page.protocol !== 'http:' || !page.port || page.origin !== expectedOrigin) {
    throw new Error('Desktop share images require the configured backend origin');
  }

  return new URL(
    `/api/v1/history/${recordId}/share-image-html`,
    page.origin
  ).toString();
}

async function renderDesktopShareImage(
  recordId,
  {
    sourceWindow = mainWindow,
    BrowserWindowClass = BrowserWindow,
    backendOrigin = '',

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Use exactly 'buy' or 'sell' (case-insensitive) as the side parameter
  2. If no side filter is wanted, omit the parameter or pass an empty string
  3. Constrain the UI dropdown / API client enum to the two valid literals
  4. If migrating from another system, map its side vocabulary ('B'/'S') to 'buy'/'sell' before calling

Example fix

# before
svc.query_trades(side="B")
# after
svc.query_trades(side="buy")
Defensive patterns

Strategy: validation

Validate before calling

VALID_SIDES = {"buy", "sell"}

def side_ok(side):
    return side is None or not side.strip() or side.strip().lower() in VALID_SIDES

Type guard

from typing import Literal

TradeSide = Literal["buy", "sell"]

def is_trade_side(value: str) -> TypeGuard[TradeSide]:
    return value.strip().lower() in {"buy", "sell"}

Try / catch

try:
    svc.query_trades(side=side)
except ValueError as exc:
    if "side must be buy or sell" in str(exc):
        raise HTTPBadRequest(detail=str(exc)) from exc
    raise

Prevention

When it happens

Trigger: GET /portfolio/trades?side=BUY%2FSELL, ?side=purchase, ?side=trade, or query_trades(side="long"). 'BUY' and 'Buy' are fine because the value is lowercased; anything else raises. Empty/whitespace side is treated as no filter, not an error.

Common situations: Clients sending synonymous terms ('b', 's', 'purchase', 'bought') instead of the enum; enum drift between an older client and the service; form selects with a stale option value after a schema change.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/5559591ab021bdb3. Report an issue: GitHub.