{"record":{"id":"944d44c36b45b04a","repo":"toeverything/AFFiNE","slug":"useraborterror","errorCode":"UserAbortError","errorMessage":"Aborted by user","messagePattern":"Aborted by user","errorType":"exception","errorClass":"BlockSuiteError","httpStatus":null,"severity":"info","filePath":"blocksuite/affine/gfx/mindmap/src/toolbar/utils/import-mindmap.ts","lineNumber":18,"sourceCode":"import { openSingleFileWith } from '@blocksuite/affine-shared/utils';\nimport { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';\nimport type { Bound } from '@blocksuite/global/gfx';\nimport c from 'simple-xml-to-json';\n\ntype MindMapNode = {\n  children: MindMapNode[];\n  text: string;\n  xywh?: string;\n  title?: string;\n  layoutType?: 'left' | 'right';\n};\n\nexport async function importMindmap(bound: Bound): Promise<MindMapNode> {\n  const file = await openSingleFileWith('MindMap');\n\n  if (!file) {\n    throw new BlockSuiteError(ErrorCode.UserAbortError, 'Aborted by user');\n  }\n\n  let result;\n\n  if (file.name.endsWith('.mm')) {\n    result = await parseMmFile(file);\n  } else if (file.name.endsWith('.opml') || file.name.endsWith('.xml')) {\n    result = await parseOPMLFile(file);\n  } else {\n    throw new BlockSuiteError(ErrorCode.ParsingError, 'Unsupported file type');\n  }\n\n  if (result) {\n    result.xywh = bound.serialize();\n  }\n\n  return result;\n}","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/blocksuite/affine/gfx/mindmap/src/toolbar/utils/import-mindmap.ts#L1-L36","documentation":"importMindmap (gfx/mindmap/src/toolbar/utils/import-mindmap.ts:13-20) opens a native single-file picker via openSingleFileWith('MindMap'); when the user dismisses the dialog the returned file is null and UserAbortError 'Aborted by user' is thrown. This is expected control flow (the user declined to choose a file), not a failure — BlockSuiteError.isFatal is false for this code.","triggerScenarios":"User clicks Cancel or presses Escape in the file picker opened from the mindmap toolbar import action; the OS dialog is closed without a selection.","commonSituations":"Any mindmap-import button handler that awaits importMindmap without distinguishing user cancellation from real failures, showing an error toast on a plain cancel.","solutions":["Catch BlockSuiteError with code UserAbortError and return silently (no toast)","Distinguish it from ParsingError so only genuine parse failures surface to the user"],"exampleFix":"// before\nconst mindmap = await importMindmap(bound); // cancel -> unhandled UserAbortError\n\n// after\ntry {\n  const mindmap = await importMindmap(bound);\n} catch (e) {\n  if (e instanceof BlockSuiteError && e.code === BlockSuiteError.ErrorCode.UserAbortError) return;\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"import { BlockSuiteError } from '@blocksuite/global/exceptions';\n\ntry {\n  const mindmap = await importMindmap(bound);\n} catch (e) {\n  if (e instanceof BlockSuiteError && e.code === BlockSuiteError.ErrorCode.UserAbortError) {\n    return; // user closed the picker: silent no-op\n  }\n  throw e;\n}","preventionTips":["Always await importMindmap inside try-catch that special-cases UserAbortError","Do not show error UI for UserAbortError — it is normal cancellation flow"],"tags":["mindmap","import","file-dialog","user-cancellation"],"backgroundTag":"user-cancelled-operation","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}