{"record":{"id":"d6e688ef003cb40a","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"field-must-contain-only-non-empty-strings","errorCode":null,"errorMessage":"{field} must contain only non-empty strings","messagePattern":"(.+?) must contain only non-empty strings","errorType":"validation","errorClass":"ParamError","httpStatus":null,"severity":"error","filePath":"sdk/memory-core/python/tencentdb_agent_memory/v3/client.py","lineNumber":69,"sourceCode":"\ndef _normalize_delete_ids(\n    field: str,\n    raw: Optional[List[str]],\n    max_items: int,\n) -> Optional[List[str]]:\n    \"\"\"归一化批量删除的 id 列表：校验非空字符串、去重（保序）、检查上限。\n\n    破坏性操作的入参在客户端就拦一道，比等服务端回 400 更早暴露问题，\n    也避免把明显不合法的批量请求发出去。\n\n    :returns: 归一化后的列表；``raw`` 为 None 时返回 None（表示\"未提供\"）。\n    \"\"\"\n    if raw is None:\n        return None\n    if not isinstance(raw, (list, tuple)):\n        raise ParamError(f\"{field} must be a list of non-empty strings\")\n    if any(not isinstance(item, str) or not item.strip() for item in raw):\n        raise ParamError(f\"{field} must contain only non-empty strings\")\n\n    seen: Dict[str, None] = {}\n    for item in raw:\n        seen.setdefault(item.strip(), None)\n    deduped = list(seen.keys())\n\n    if len(deduped) > max_items:\n        raise ParamError(f\"{field} accepts at most {max_items} items, got {len(deduped)}\")\n    return deduped\n\n\ndef _validate_construction(team_id: str, agent_id: str, user_id: str) -> None:\n    \"\"\"v3 构造时 team+agent+user 必填，任一缺失立刻 ParamError，避免 422 才暴露。\n\n    session_id 不在构造时强校验（L2/L3 接口不需要）；L0/L1 方法调用时再单独校验。\n    \"\"\"\n    missing = [\n        name for name, val in (","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/sdk/memory-core/python/tencentdb_agent_memory/v3/client.py#L51-L87","documentation":"_normalize_delete_ids validates that list-style delete inputs (message_ids, session_ids, ids, memory_ids) contain only strings that are non-empty after whitespace stripping. Any None, non-str element (int, dict, empty string) triggers this ParamError. It is a client-side guard so malformed IDs never reach the server.","triggerScenarios":"Calling delete_conversation, delete_atomic, or clear_chat_memory with a list containing non-string items (e.g. ints from JSON without str conversion), empty strings, whitespace-only strings, or None elements inside the list.","commonSituations":"IDs parsed from JSON/YAML where numeric IDs stay unquoted; DB drivers returning ints; f-string interpolation producing 'None' or empty values; collecting IDs from a dict iteration that yields non-strings.","solutions":["Convert every element to a stripped non-empty string before calling: ids=[str(i).strip() for i in raw_ids if str(i).strip()]","Check element types before the call: all(isinstance(x, str) and x.strip() for x in ids)","Fix the source producing the IDs (JSON parsing, DB row extraction) to emit strings","If you may pass empty lists, that is allowed — only list ELEMENTS must be non-empty strings"],"exampleFix":"// before\nclient.delete_atomic(ids=[12345, \"\", None])\n// after\nclean = [str(i).strip() for i in raw_ids if isinstance(i, str) and i.strip()]\nclient.delete_atomic(ids=clean)","handlingStrategy":"validation","validationCode":"def valid_delete_ids(ids):\n    return isinstance(ids, (list, tuple)) and all(isinstance(i, str) and i.strip() for i in ids)\n# call only if valid_delete_ids(message_ids)","typeGuard":"def as_str_list(raw) -> list[str] | None:\n    if isinstance(raw, (list, tuple)) and all(isinstance(i, str) for i in raw):\n        return [i for i in raw if i.strip()]\n    return None","tryCatchPattern":"try:\n    client.delete_conversation(message_ids=ids)\nexcept ParamError as e:\n    logger.error(\"bad delete ids: %s\", e)\n    ids = [str(i).strip() for i in ids if str(i).strip()]\n    client.delete_conversation(message_ids=ids)","preventionTips":["Coerce all id sources to stripped strings at ingestion time","Add a shared normalize_ids helper used by every caller","Type-annotate id params as list[str] and run mypy","Reject numeric ids at the JSON parse boundary, not at the SDK call"],"tags":["python","validation","parameter-error"],"backgroundTag":"invalid-parameter-list","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}