{"record":{"id":"0c82cb0d25cb19a1","repo":"ZhuLinsen/daily_stock_analysis","slug":"desktop-window-is-unavailable","errorCode":null,"errorMessage":"Desktop window is unavailable","messagePattern":"Desktop window is unavailable","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/dsa-desktop/main.js","lineNumber":1384,"sourceCode":"    throw new Error('Desktop share images require the configured backend origin');\n  }\n\n  return new URL(\n    `/api/v1/history/${recordId}/share-image-html`,\n    page.origin\n  ).toString();\n}\n\nasync function renderDesktopShareImage(\n  recordId,\n  {\n    sourceWindow = mainWindow,\n    BrowserWindowClass = BrowserWindow,\n    backendOrigin = '',\n  } = {}\n) {\n  if (!sourceWindow || sourceWindow.isDestroyed() || !sourceWindow.webContents) {\n    throw new Error('Desktop window is unavailable');\n  }\n\n  const targetUrl = buildDesktopShareImageUrl(\n    sourceWindow.webContents.getURL(),\n    recordId,\n    backendOrigin\n  );\n  let renderWindow = null;\n  try {\n    renderWindow = new BrowserWindowClass({\n      show: false,\n      width: DESKTOP_SHARE_IMAGE_WIDTH,\n      height: DESKTOP_SHARE_IMAGE_INITIAL_HEIGHT,\n      ...(isMac ? { enableLargerThanScreen: true } : {}),\n      useContentSize: true,\n      backgroundColor: '#eef4fd',\n      webPreferences: {\n        nodeIntegration: false,","sourceCodeStart":1366,"sourceCodeEnd":1402,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/apps/dsa-desktop/main.js#L1366-L1402","documentation":"Raised by PortfolioService.query_cash_ledger when the direction filter, after strip+lowercase, is not in VALID_CASH_DIRECTIONS = {'in','out'} (portfolio_service.py:37). Checked before repo.query_cash_ledger executes.","triggerScenarios":"GET /portfolio/cash-ledger?direction=deposit, ?direction=inflow, ?direction=IN%2FOUT, or query_cash_ledger(direction=\"credit\"). 'IN'/'Out' pass due to lowercasing; empty/whitespace means no filter.","commonSituations":"Clients modeling cash movement with debit/credit or deposit/withdraw vocabulary instead of in/out; enum mismatch after importing data from broker exports; frontend select options not updated to the service contract.","solutions":["Use exactly 'in' or 'out' (case-insensitive)","Omit the parameter for an unfiltered ledger query","Map broker vocabulary (deposit->in, withdrawal->out) in an adapter layer before calling","Pin the valid values in the API client schema so invalid states are unrepresentable"],"exampleFix":"# before\nsvc.query_cash_ledger(direction=\"deposit\")\n# after\nsvc.query_cash_ledger(direction=\"in\")","handlingStrategy":"validation","validationCode":"VALID_CASH_DIRECTIONS = {\"in\", \"out\"}\n\ndef direction_ok(direction):\n    return direction is None or not direction.strip() or direction.strip().lower() in VALID_CASH_DIRECTIONS","typeGuard":"from typing import Literal, TypeGuard\n\nCashDirection = Literal[\"in\", \"out\"]\n\ndef is_cash_direction(value: str) -> TypeGuard[CashDirection]:\n    return value.strip().lower() in {\"in\", \"out\"}","tryCatchPattern":"try:\n    svc.query_cash_ledger(direction=d)\nexcept ValueError as exc:\n    if \"direction must be in or out\" in str(exc):\n        raise HTTPBadRequest(detail=str(exc)) from exc\n    raise","preventionTips":["Pin the client enum to in/out; reject debit/credit synonyms at the edge","Map deposit/withdraw vocabulary in an adapter layer","Empty string means 'no filter', not 'all' — decide deliberately"],"tags":["portfolio","validation","enum","cash-ledger"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}