{"record":{"id":"47b063602c870198","repo":"HKUDS/Vibe-Trading","slug":"memory-name-must-not-be-empty-or-whitespace-only","errorCode":null,"errorMessage":"memory name must not be empty or whitespace-only","messagePattern":"memory name must not be empty or whitespace-only","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/memory/persistent.py","lineNumber":497,"sourceCode":"    def add(\n        self,\n        name: str,\n        content: str,\n        memory_type: str = \"project\",\n        description: str = \"\",\n    ) -> Optional[Path]:\n        \"\"\"Save a new memory entry and update the index.\"\"\"\n        if _is_quality_enabled() and self.is_duplicate(name, description, content):\n            logger.debug(\n                \"Duplicate memory write blocked within %.0fs window: %s\",\n                DEDUP_WINDOW_SECONDS,\n                name,\n            )\n            return None\n\n        stripped_name = name.strip()\n        if not stripped_name:\n            raise ValueError(\"memory name must not be empty or whitespace-only\")\n        if memory_type not in MEMORY_TYPES:\n            raise ValueError(f\"memory_type must be one of: {', '.join(MEMORY_TYPES)}\")\n\n        slug = _SLUG_DISALLOWED_RE.sub(\"_\", stripped_name.lower())[:60]\n        if slug.strip(\"_\") == \"\":\n            digest = hashlib.sha256(stripped_name.encode(\"utf-8\")).hexdigest()[:6]\n            slug = f\"{slug}_{digest}\" if slug else digest\n\n        from src.config.accessor import get_env_config\n        if get_env_config().memory.hierarchy_enabled:\n            from src.memory.hierarchy import MemoryHierarchy\n            hierarchy = MemoryHierarchy(self._dir)\n            # route_entry() treats its second argument as the leaf filename\n            # verbatim, so the \".md\" has to be here: a bare slug wrote entries\n            # with no suffix, and every scan filters on suffix == \".md\", which\n            # made them invisible to list_entries() and find(). The category\n            # directory already carries the type, and the name must match what\n            # recover_extensionless_entries() renames orphans to, or the same","sourceCodeStart":479,"sourceCodeEnd":515,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/memory/persistent.py#L479-L515","documentation":"PersistentMemory.add rejects a memory name that is empty after stripping. Names generate the storage slug, so a blank name cannot be persisted and is rejected before type checks or slug generation.","triggerScenarios":"Calling add(name=\"\", ...), add(name=\"   \", ...), or add(name=None) where None is stringified to a blank; programmatic callers passing unvalidated identifiers.","commonSituations":"Batch ingestion loops where some records lack a name field, LLM/tool output used directly as memory names, or whitespace names from copy-paste.","solutions":["Validate the name is non-blank before calling add","Skip or log-and-continue records with blank names in batch loops","Default to a derived name (e.g. timestamp or content digest) when the source field is missing"],"exampleFix":"# before\nmem.add(name=user_title, memory_type=\"observation\", content=text)\n# after\nif user_title and user_title.strip():\n    mem.add(name=user_title.strip(), memory_type=\"observation\", content=text)","handlingStrategy":"validation","validationCode":"name = (name or '').strip()\nif not name:\n    log.warning('skipping memory with blank name'); return None\nmem.add(name=name, memory_type=memory_type, content=content)","typeGuard":"def is_valid_memory_name(n) -> bool:\n    return isinstance(n, str) and bool(n.strip())","tryCatchPattern":"try:\n    mem.add(name=name, memory_type=memory_type, content=content)\nexcept ValueError as exc:\n    if 'must not be empty' in str(exc):\n        mem.add(name=derived_fallback_name, memory_type=memory_type, content=content)","preventionTips":["Validate generated/LLM-provided names before persisting","Skip-and-log blank records in batch ingestion","Default to a deterministic fallback name (digest/timestamp)"],"tags":["python","validation","required-field","memory"],"backgroundTag":"missing-required-field","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}