{"record":{"id":"995a444597891646","repo":"mem0ai/mem0","slug":"failed-to-delete-memory-with-id-vectorid","errorCode":null,"errorMessage":"Failed to delete memory with ID ${vectorId}","messagePattern":"Failed to delete memory with ID (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mem0-ts/src/oss/src/vector_stores/redis.ts","lineNumber":633,"sourceCode":"  }\n\n  async delete(vectorId: string): Promise<void> {\n    await this.initialize();\n    try {\n      // Check if memory exists first\n      const key = `${this.indexPrefix}:${vectorId}`;\n      const exists = await this.client.exists(key);\n\n      if (!exists) {\n        console.warn(`Memory with ID ${vectorId} does not exist`);\n        return;\n      }\n\n      // Delete the memory\n      const result = await this.client.del(key);\n\n      if (!result) {\n        throw new Error(`Failed to delete memory with ID ${vectorId}`);\n      }\n\n      console.log(`Successfully deleted memory with ID ${vectorId}`);\n    } catch (error) {\n      console.error(\"Error deleting memory:\", error);\n      throw error;\n    }\n  }\n\n  async deleteCol(): Promise<void> {\n    await this.initialize();\n    await this.client.ft.dropIndex(this.indexName);\n  }\n\n  async list(\n    filters?: SearchFilters,\n    topK: number = 100,\n  ): Promise<[VectorStoreResult[], number]> {","sourceCodeStart":615,"sourceCodeEnd":651,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0-ts/src/oss/src/vector_stores/redis.ts#L615-L651","documentation":"During deleteVector, the Redis store checks the key exists, then calls DEL. Redis DEL returns the number of keys removed; a 0 return after the existence check passed means the delete did not actually happen (e.g. the key expired or was deleted concurrently between the two calls). The store throws rather than silently reporting success.","triggerScenarios":"Two concurrent delete calls for the same memory ID where one wins; a key TTL expiring between the EXISTS check and the DEL call; manual/external deletion racing with the application.","commonSituations":"Duplicate delete requests from retries or idempotency-unaware clients; background cleanup jobs deleting the same keys; short TTLs configured on memory keys.","solutions":["Treat this error as benign in concurrent-delete flows: catch it and verify with a follow-up EXISTS that the key is gone","Make delete operations idempotent on the caller side (deduplicate by vector ID, or ignore failures after a successful existence re-check)","Remove conflicting TTLs or external jobs that delete the same keyspace"],"exampleFix":"// before\nawait redisVs.deleteVector(id); // may throw on concurrent delete\n\n// after\ntry {\n  await redisVs.deleteVector(id);\n} catch (e) {\n  if (!(e.message.includes('Failed to delete'))) throw e;\n  const still = await client.exists(`mem0:${id}`);\n  if (still) throw e; // genuinely failed\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await redisVs.deleteVector(id);\n} catch (e) {\n  const msg = e instanceof Error ? e.message : '';\n  if (!msg.includes('Failed to delete')) throw e;\n  // concurrent delete: confirm the key is actually gone\n  const stillExists = await rawClient.exists(`mem0:${id}`);\n  if (stillExists) throw e;\n}","preventionTips":["Make delete flows idempotent: treat 'does not exist' as success","Deduplicate delete requests by ID before issuing them","Avoid external jobs or TTLs deleting the same keyspace your app manages"],"tags":["redis","delete","race-condition","concurrency","typescript"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}