{"record":{"id":"eed58bd1002a967a","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"sqlite-deletel0bysession-requires-a-non-empty-se","errorCode":null,"errorMessage":"[sqlite] deleteL0BySession requires a non-empty sessionId","messagePattern":"\\[sqlite\\] deleteL0BySession requires a non-empty sessionId","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"MemoryCore/src/core/store/sqlite.ts","lineNumber":2687,"sourceCode":"      const rows = this.db.prepare(dataSql).all(...params, filter.limit, filter.offset) as unknown as L1RecordRow[];\n\n      return { rows, total };\n    } catch (err) {\n      this.logger?.warn(`[sqlite] queryL1Paginated failed: ${err instanceof Error ? err.message : String(err)}`);\n      return { rows: [], total: 0 };\n    }\n  }\n\n  /**\n   * Delete all L0 messages belonging to a session.\n   * Returns the count of actually deleted rows.\n   */\n  deleteL0BySession(sessionId: string, filter?: IsolationFilter): number {\n    // 空 sessionId 会匹配所有 session_key/session_id 为空的历史 legacy 行，\n    // 造成远超预期的删除范围。空 session 不是有效删除目标，直接拒绝。\n    const sessionIdTrimmed = (sessionId ?? \"\").trim();\n    if (!sessionIdTrimmed) {\n      throw new Error(\"[sqlite] deleteL0BySession requires a non-empty sessionId\");\n    }\n\n    if (this.degraded) return 0;\n\n    try {\n      // 必须把 rowMatchesIsolation 会检查的**所有**列都取出来\n      // （team_id / task_id 早期漏取，导致带 teamId 的 isolation filter\n      // 永远判不匹配 → 按session 删除恒返回 0）。\n      const rows = this.db.prepare(\n        \"SELECT record_id, session_key, session_id, team_id, task_id, user_id, agent_id FROM l0_conversations WHERE session_key = ? OR session_id = ?\"\n      ).all(sessionIdTrimmed, sessionIdTrimmed) as Array<{\n        record_id: string; session_key: string; session_id: string;\n        team_id: string; task_id: string; user_id: string; agent_id: string;\n      }>;\n\n      if (rows.length === 0) return 0;\n\n      this.db.exec(\"BEGIN\");","sourceCodeStart":2669,"sourceCodeEnd":2705,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/MemoryCore/src/core/store/sqlite.ts#L2669-L2705","documentation":"deleteL0BySession refuses empty session IDs because an empty sessionId would match legacy rows with empty session_key/session_id, deleting far more data than intended. The guard trims the input and rejects empty results to prevent accidental mass deletion.","triggerScenarios":"Calling VectorStore.deleteL0BySession(sessionId) with undefined, null, '', or a whitespace-only sessionId.","commonSituations":"Session ID lookup returning undefined before the delete call, a message object lacking session metadata, or string interpolation of an unset variable producing ''.","solutions":["Obtain a valid sessionId from the session/message object before calling deleteL0BySession","Validate non-empty sessionId in your own code before invoking the API","If the goal is to clear all rows, use an explicit purge/clear API rather than passing an empty sessionId"],"exampleFix":"// before\nstore.deleteL0BySession(msg.sessionId ?? '');\n// after\nif (msg.sessionId && msg.sessionId.trim()) {\n  store.deleteL0BySession(msg.sessionId);\n}","handlingStrategy":"validation","validationCode":"function assertSessionId(id) {\n  const t = (id ?? '').trim();\n  if (!t) throw new Error('sessionId required for deleteL0BySession');\n  return t;\n}\nstore.deleteL0BySession(assertSessionId(msg.sessionId));","typeGuard":"function hasSessionId(v): v is string {\n  return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":"try {\n  store.deleteL0BySession(sessionId);\n} catch (e) {\n  if (String(e.message).includes('non-empty sessionId')) {\n    logger.warn(`Skipped L0 delete: sessionId missing for message`);\n    return 0;\n  }\n  throw e;\n}","preventionTips":["Never default sessionId to '' with ?? or ||; keep it undefined so guards fire","Derive sessionId from validated session objects only","Add tests covering delete calls with missing session metadata"],"tags":["validation","sqlite","data-deletion","guard"],"backgroundTag":"empty-required-parameter","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}