ZhuLinsen/daily_stock_analysis · warning · Error

Desktop backend URL is unavailable

Error message

Desktop backend URL is unavailable

What it means

Raised by PortfolioService.query_trades when a non-empty symbol filter produces no usable filter values. _build_symbol_filter_values (portfolio_service.py:1299) normalizes the symbol via canonical_stock_code/normalize_stock_code; if normalization yields an empty string, the filter list is empty and the service refuses to run an unfiltered query that the user intended to be filtered.

Source

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

}

function buildMainPageUrl(port, timestamp = Date.now(), host = DESKTOP_BACKEND_DEFAULT_HOST) {
  const url = new URL(buildBackendUrl(host, port, '/'));
  url.searchParams.set('desktop_version', resolveDesktopVersion() || 'unknown');
  url.searchParams.set('cache_bust', String(timestamp));
  return url.toString();
}

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();

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Send a real ticker in a supported format ('600519', 'HK00700', 'AAPL')
  2. If the intent is 'no filter', omit the symbol parameter entirely or pass an empty string
  3. Validate symbols against the same canonicalizer (data_provider.base.canonical_stock_code) before calling query_trades
  4. Sanitize upstream data feeds that inject placeholder values into symbol fields

Example fix

# before
svc.query_trades(symbol="-")
# after
svc.query_trades(symbol=None)  # no symbol filter
Defensive patterns

Strategy: validation

Validate before calling

from data_provider.base import canonical_stock_code, normalize_stock_code

def symbol_filter_ok(symbol):
    if symbol is None or not symbol.strip():
        return True  # no filter intended
    return bool(canonical_stock_code(normalize_stock_code(symbol.strip())))

Type guard

def is_queryable_symbol(symbol: str | None) -> bool:
    """False when query_trades would raise 'symbol is invalid'."""
    if not (symbol or "").strip():
        return True
    return bool(canonical_stock_code(symbol))

Try / catch

try:
    svc.query_trades(symbol=s)
except ValueError as exc:
    if "symbol is invalid" in str(exc):
        return {"items": [], "total": 0}  # treat as no matches
    raise

Prevention

When it happens

Trigger: GET /portfolio/trades?symbol=%20%20%20%20 or ?symbol=@@@, or query_trades(symbol="NOSUCH!!!") where canonicalization returns ''. Note the guard is only reached when symbol.strip() is truthy, so purely empty strings skip filtering instead of raising.

Common situations: Passing punctuation-only or placeholder strings ('-', 'n/a', '--') from a CSV import or UI dropdown; symbols containing only whitespace that survived an outer strip but fail canonicalization; test fixtures with invented tickers the provider cannot canonicalize.

Related errors


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