yikart/AiToEarn · error · AppException
DraftGenerationMemoryNotFound
DraftGenerationMemoryNotFound
Error message
ResponseCode.DraftGenerationMemoryNotFound
What it means
deleteItem() calls the repository to delete a draft-generation memory item by (userId, itemId) and throws AppException(ResponseCode.DraftGenerationMemoryNotFound) when no document was deleted — i.e. the item does not exist for that user.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/draft-generation/draft-generation-memory.service.ts:53
async listMemories(userId: string, contentType?: DraftGenerationMemoryContentType) {
return await this.draftGenerationMemoryRepository.listByUserId(userId, contentType)
}
async getPlannerMemoryContext(userId: string, contentType: DraftGenerationMemoryContentType): Promise<PlannerMemoryContext> {
const memory = await this.draftGenerationMemoryRepository.getByUserIdAndContentType(userId, contentType)
if (!memory) {
return { memoryItems: [] }
}
return {
memoryItems: (memory.items ?? []).map(item => item.text),
}
}
async deleteItem(userId: string, itemId: string) {
const memory = await this.draftGenerationMemoryRepository.deleteItemByUserIdAndItemId(userId, itemId)
if (!memory) {
throw new AppException(ResponseCode.DraftGenerationMemoryNotFound)
}
return memory
}
async regenerateMemory(userId: string, contentType: DraftGenerationMemoryContentType, plannerModel?: string) {
const { aiLogs, materials } = await this.listMemorySamples(userId, contentType)
const sampleCount = aiLogs.length + materials.length
const now = new Date()
if (sampleCount === 0) {
const emptyMemory = await this.draftGenerationMemoryRepository.updateByUserIdAndContentType(userId, contentType, {
$set: { userId, contentType, items: [], sampleCount: 0, lastGeneratedAt: now },
})
if (!emptyMemory) {
throw new AppException(ResponseCode.DraftGenerationMemoryNotFound)
}
return emptyMemory
}View on GitHub (pinned to d3aa8bea5b)
Solutions
- Fetch the current memory list first and delete only existing item ids
- Handle DraftGenerationMemoryNotFound idempotently on the client (treat second delete as success)
- Verify the itemId and userId pairing — ids are scoped per user
Example fix
// before
await memoryApi.deleteItem(itemId) // throws if already gone
// after
try { await memoryApi.deleteItem(itemId) } catch (e) { if (e.code !== 'DraftGenerationMemoryNotFound') throw e } Defensive patterns
Strategy: try-catch
Validate before calling
const memory = await memoryRepo.getByUserIdAndItemId(userId, itemId); if (!memory) return; // already deleted, skip call
Try / catch
try { await draftGenerationMemoryService.deleteItem(userId, itemId) } catch (e) { if (e instanceof AppException && e.code === ResponseCode.DraftGenerationMemoryNotFound) return; throw e } Prevention
- Treat delete-as-idempotent: refresh the list after each delete and ignore NotFound on retries
- Disable delete buttons for items already removed in the UI
- Scope item ids per user and never reuse ids across accounts
When it happens
Trigger: Calling deleteItem with an itemId that was already deleted, never existed, or belongs to a different userId; stale item id in the client after another device removed it.
Common situations: Double-click delete issuing two DELETE calls; client caches an old memory list; id copied from another user's session or environment.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/c18195b9d16d48e6.
Report an issue: GitHub.