{"record":{"id":"cad25a3132b37434","repo":"stablyai/orca","slug":"label-is-required","errorCode":null,"errorMessage":"${label} is required","messagePattern":"(.+?) is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/filesystem-download-folder.ts","lineNumber":15,"sourceCode":"import { BrowserWindow, dialog, ipcMain } from 'electron'\nimport { randomUUID } from 'node:crypto'\nimport { rm, stat } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { getRuntimePathBasename } from '../../shared/cross-platform-path'\nimport { sanitizeLocalDownloadFilename } from '../local-download-filename'\nimport { promoteLocalDownloadedFolder } from '../local-downloaded-folder-promotion'\nimport { requireSshFilesystemProvider } from '../providers/ssh-filesystem-dispatch'\nimport { isENOENT } from './filesystem-auth'\n\ntype DownloadFolderResult = { canceled: true } | { canceled: false; destinationPath: string }\n\nfunction validateRequiredString(value: unknown, label: string): string {\n  if (typeof value !== 'string' || value.trim() === '') {\n    throw new Error(`${label} is required`)\n  }\n  return value\n}\n\nfunction createSiblingTransferPath(destinationPath: string, suffix: string): string {\n  // Why: promotion uses rename/no-clobber operations that must stay on the\n  // destination volume, so transfer paths intentionally remain siblings.\n  return join(dirname(destinationPath), `.${randomUUID()}.${suffix}`)\n}\n\nasync function assertDownloadFolderDestinationAvailable(destinationPath: string): Promise<void> {\n  try {\n    await stat(destinationPath)\n  } catch (error) {\n    if (isENOENT(error)) {\n      return\n    }\n    throw error","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/filesystem-download-folder.ts#L1-L33","documentation":"Thrown by validateRequiredString() inside the 'fs:downloadFolder' IPC handler when either args.dirPath or args.connectionId is not a non-empty string. The guard rejects undefined, non-string, and whitespace-only values before any SSH or filesystem work begins, so the message reports the offending field name (the ${label}). It is a contract violation between the renderer and the main-process handler, not a filesystem or network failure.","triggerScenarios":"The renderer invokes ipcRenderer.invoke('fs:downloadFolder', { dirPath, connectionId }) with dirPath undefined/empty (e.g. the user triggered download on a non-resolved tree node) or with connectionId missing/cleared after the SSH target was disconnected and the connection id was reset to undefined.","commonSituations":"A UI code path that offers 'Download folder' before the selected node has a concrete remote path; a stale handler binding that still fires after disconnect cleared connectionId; a refactored renderer payload that renamed the fields; testing the IPC channel directly with partial args.","solutions":["Ensure the renderer only enables the Download action once both a concrete dirPath and an active connectionId are available, and pass them in the invoke payload.","Guard in the renderer: skip the call when typeof dirPath !== 'string' or !connectionId.","If this fires after a disconnect, re-establish the SSH connection so a fresh connectionId is set before retrying the download."],"exampleFix":"// before\nwindow.api.fs.downloadFolder({ dirPath: selectedNode?.path, connectionId })\n// after\nif (typeof selectedNode?.path === 'string' && selectedNode.path.trim() && connectionId) {\n  await window.api.fs.downloadFolder({ dirPath: selectedNode.path, connectionId })\n}","handlingStrategy":"validation","validationCode":"// Renderer: validate both IPC args before invoking fs:downloadFolder\nfunction canDownloadFolder(dirPath: unknown, connectionId: unknown): boolean {\n  return typeof dirPath === 'string' && dirPath.trim().length > 0 &&\n         typeof connectionId === 'string' && connectionId.trim().length > 0\n}\nif (!canDownloadFolder(selectedPath, connId)) { /* disable action */ }","typeGuard":"function isNonEmptyString(v: unknown): v is string {\n  return typeof v === 'string' && v.trim().length > 0\n}","tryCatchPattern":null,"preventionTips":["Gate the Download action in the UI on a concrete dirPath and an active connectionId.","Clear stale connectionId references in the renderer when the SSH target disconnects.","Add a renderer-side unit test that asserts both fields are passed on every invoke."],"tags":["ipc","validation","ssh","renderer-contract"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}