{"record":{"id":"e59a59b86645084c","repo":"danielmiessler/Fabric","slug":"no-file-selected","errorCode":null,"errorMessage":"No file selected","messagePattern":"No file selected","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"info","filePath":"web/src/lib/store/session-store.ts","lineNumber":78,"sourceCode":"      sessions.set([]);\n    }\n  },\n\n  async exportToFile(messages: Message[]) {\n    try {\n      await saveToFile(messages, 'session-history.json');\n      toastService.success('Session exported successfully');\n    } catch (error) {\n      toastService.error('Failed to export session');\n      throw error;\n    }\n  },\n\n  async importFromFile(): Promise<Message[]> {\n    try {\n      const file = await openFileDialog('.json');\n      if (!file) {\n        throw new Error('No file selected');\n      }\n\n      const content = await readFileAsJson<Message[]>(file);\n      if (!Array.isArray(content)) {\n        throw new Error('Invalid session file format');\n      }\n\n      toastService.success('Session imported successfully');\n      return content;\n    } catch (error) {\n      toastService.error(error instanceof Error ? error.message : 'Failed to import session');\n      throw error;\n    }\n  },\n\n  async loadSessionMessages(sessionName: string): Promise<Message[]> {\n    try {\n      const response = await fetch(`/api/sessions/${sessionName}`);","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/danielmiessler/Fabric/blob/338b89cfe97ab2d12ce30ce8b5449857a841366d/web/src/lib/store/session-store.ts#L60-L96","documentation":"session-store.importFromFile throws 'No file selected' when the file-open dialog resolves without a file — the user cancelled the picker or it was dismissed. This is a control-flow signal more than a failure: nothing was imported and nothing is wrong.","triggerScenarios":"User clicks Cancel/Escape in the .json file picker; dialog closed without a selection; openFileDialog returning undefined/null on cancellation.","commonSituations":"Any import flow where cancellation is a normal path but the code treats a missing file as an error, showing an error toast for a simple cancel.","solutions":["Treat this as cancellation: catch it (or check the message) and return quietly instead of toasting an error","Distinguish cancel from real failures by returning a sentinel from the dialog wrapper instead of throwing"],"exampleFix":"// before\nconst file = await openFileDialog('.json');\nif (!file) {\n  throw new Error('No file selected');\n}\n\n// after\nconst file = await openFileDialog('.json');\nif (!file) {\n  return []; // user cancelled; nothing to import\n}","handlingStrategy":"validation","validationCode":"const file = await openFileDialog('.json');\nif (!file) return []; // user cancelled — nothing to do","typeGuard":"function isCancelError(e: unknown): boolean {\n  return e instanceof Error && e.message === 'No file selected';\n}","tryCatchPattern":"try { messages = await importFromFile(); }\ncatch (e) {\n  if (isCancelError(e)) return; // silent — cancellation is not an error\n  toast.error('Import failed');\n}","preventionTips":["Treat a null dialog result as cancellation, not an exception","Validate the parsed JSON is an array before using it (the store already does)"],"tags":["file-dialog","ui","cancel-handling"],"backgroundTag":null,"analyzedSha":"338b89cfe97ab2d12ce30ce8b5449857a841366d","analyzedAt":"2026-08-15T11:38:51.759Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}