{"record":{"id":"be70a9b596835a2e","repo":"linshenkx/prompt-optimizer","slug":"context-error-codes-import-format-error-be70a9","errorCode":"CONTEXT_ERROR_CODES.IMPORT_FORMAT_ERROR","errorMessage":"Invalid context bundle format","messagePattern":"Invalid context bundle format","errorType":"error_code","errorClass":"ContextError","httpStatus":null,"severity":"error","filePath":"packages/core/src/services/context/repo.ts","lineNumber":441,"sourceCode":"      return doc;\n    });\n  }\n\n  async exportAll(): Promise<ContextBundle> {\n    const doc = await this.getStoreDoc();\n    \n    return {\n      type: 'context-bundle',\n      version: CONTEXT_STORE_VERSION,\n      currentId: doc.currentId,\n      contexts: Object.values(doc.contexts)\n    };\n  }\n\n  async importAll(bundle: ContextBundle, mode: ImportMode): Promise<ImportResult> {\n    // 验证bundle格式\n    if (!bundle || bundle.type !== 'context-bundle' || !Array.isArray(bundle.contexts)) {\n      throw new ContextError(CONTEXT_ERROR_CODES.IMPORT_FORMAT_ERROR, 'Invalid context bundle format');\n    }\n\n    if (bundle.contexts.length === 0) {\n      throw new ContextError(CONTEXT_ERROR_CODES.IMPORT_FORMAT_ERROR, 'Context bundle must contain at least one context');\n    }\n\n    let imported = 0;\n    let skipped = 0;\n    let predefinedVariablesRemoved = 0;\n    const idMapping: Record<string, string> = {};\n\n    await this.updateStoreDoc(doc => {\n      const now = getCurrentISOTime();\n\n      switch (mode) {\n        case 'replace':\n          // 替换模式：清空现有数据\n          doc.contexts = {};","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/core/src/services/context/repo.ts#L423-L459","documentation":"extractVariable validates the selection indices before substitution: startIndex must be >= 0, endIndex must not exceed messageContent.length, and startIndex must be strictly less than endIndex. Any violation throws 'Invalid selection range'. This guards substring() from producing wrong results.","triggerScenarios":"Calling extractVariable with startIndex < 0, endIndex > message length, startIndex >= endIndex, or indices computed against a different (stale/edited) version of messageContent.","commonSituations":"User edits the message after selection indices were captured, shifting offsets; off-by-one when computing endIndex; empty selection (start === end) submitted; stale state after undo/redo.","solutions":["Recompute indices against the current messageContent right before calling extractVariable","Disable the extract button for empty selections (start === end)","Clamp/validate indices in the UI layer with the same rules before invoking the service"],"exampleFix":"// before\nconst r = extractor.extractVariable(name, content, selected, selectionStart, selectionEnd)\n\n// after\nif (selectionStart < 0 || selectionEnd > content.length || selectionStart >= selectionEnd) {\n  throw new Error('Invalid selection range')\n}\nconst r = extractor.extractVariable(name, content, content.slice(selectionStart, selectionEnd), selectionStart, selectionEnd)","handlingStrategy":"validation","validationCode":"function isValidRange(content: string, start: number, end: number): boolean {\n  return start >= 0 && end <= content.length && start < end\n}\nif (!isValidRange(messageContent, startIndex, endIndex)) {\n  throw new Error('Selection is empty or out of bounds')\n}","typeGuard":"type ValidRange = { start: number; end: number }\nfunction isValidRange(r: { start: number; end: number }, len: number): r is ValidRange {\n  return r.start >= 0 && r.end <= len && r.start < r.end\n}","tryCatchPattern":"try {\n  const r = extractor.extractVariable(name, content, selectedText, start, end)\n} catch (error) {\n  if (error instanceof Error && error.message === 'Invalid selection range') {\n    // recompute selection from the live editor and retry once\n    return reselectAndRetry()\n  }\n  throw error\n}","preventionTips":["Recompute indices against the current content immediately before the call","Disable extract actions for empty selections (start === end)","Invalidate stored selections whenever the editor content changes"],"tags":["validation","selection-range","user-input","off-by-one"],"backgroundTag":"input-validation-failed","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}