{"record":{"id":"b65287bb59c77480","repo":"linshenkx/prompt-optimizer","slug":"data-property-is-missing-or-not-an-object","errorCode":null,"errorMessage":"\"data\" property is missing or not an object","messagePattern":"\"data\" property is missing or not an object","errorType":"validation","errorClass":"DataInvalidFormatError","httpStatus":null,"severity":"warning","filePath":"packages/core/src/services/data/manager.ts","lineNumber":115,"sourceCode":"    let exportData: any;\n\n    try {\n      exportData = JSON.parse(dataString);\n    } catch (error) {\n      throw new DataInvalidJsonError(error instanceof Error ? error.message : String(error))\n    }\n\n    if (!exportData || typeof exportData !== 'object' || Array.isArray(exportData)) {\n      throw new DataInvalidFormatError('Data must be an object')\n    }\n\n    // Support both old and new format for backward compatibility\n    let dataToImport: Record<string, any>;\n\n    // New format: { version: 1, data: { ... } }\n    if (exportData.version) {\n      if (!exportData.data || typeof exportData.data !== 'object' || Array.isArray(exportData.data)) {\n        throw new DataInvalidFormatError('\"data\" property is missing or not an object')\n      }\n      dataToImport = exportData.data;\n    }\n    // Old format: direct data object { history: [...], models: [...], ... }\n    else if (exportData.history || exportData.models || exportData.imageModels || exportData.userTemplates || exportData.userSettings || exportData.contexts) {\n      dataToImport = exportData;\n    }\n    else {\n      throw new DataInvalidFormatError('Unrecognized data structure')\n    }\n\n    const errors: string[] = [];\n\n    // 使用各服务的importData接口\n    const serviceMap = [\n      { service: this.historyManager, dataKey: 'history' },\n      { service: this.modelManager, dataKey: 'models' },\n      ...(this.imageModelManager ? [{ service: this.imageModelManager, dataKey: 'imageModels' }] : []),","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/core/src/services/data/manager.ts#L97-L133","documentation":"OptimizationError thrown by validateMessageOptimizationRequest when no element of request.messages has an id equal to request.selectedMessageId. The optimizer locates the selected message in the array to know what to rewrite; a mismatch (stale id, different id format) fails here.","triggerScenarios":"Passing an id from a different message list than the one in messages — e.g. messages reloaded/regenerated (new ids) while selectedMessageId still holds the old id, or id type mismatch (number vs string).","commonSituations":"Chat regenerated after edit so message ids changed, optimistic local ids ('tmp-1') not matching server ids, strict vs loose equality on ids, pagination truncating the array so the selected message falls outside it.","solutions":["Re-derive selectedMessageId from the same array you pass: request.messages.find(m => m.id === selectedId) before calling.","If using temporary local ids, replace them with persisted ids once the conversation syncs.","Ensure id types match on both sides (always strings, or always numbers).","If the list may have truncated, refetch full history before optimizing."],"exampleFix":"// before\nawait promptService.optimizeMessage({ selectedMessageId: selectedId, messages, modelKey });\n\n// after\nconst exists = messages.some(m => m.id === selectedId);\nif (!exists) throw new Error('Selection is stale — message list changed');\nawait promptService.optimizeMessage({ selectedMessageId: selectedId, messages, modelKey });","handlingStrategy":"validation","validationCode":"const found = messages.some(m => m.id === request.selectedMessageId);\nif (!found) throw new Error('Selection stale — refetch messages');","typeGuard":"function selectionExists(messages: {id: string}[], id: string): boolean {\n  return messages.some(m => m.id === id);\n}","tryCatchPattern":"try { await svc.optimizeMessage(req); } catch (e) { if (e instanceof OptimizationError && /not found in messages/.test(e.message)) { await refreshMessages(); } }","preventionTips":["Derive selectedMessageId from the same array passed in","Replace temp ids after persistence","Keep id types consistent (string vs number)"],"tags":["validation","message-optimization","stale-id"],"backgroundTag":"entity-not-found","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}