{"record":{"id":"47813175b0d01f9f","repo":"HKUDS/Vibe-Trading","slug":"memory-type-must-be-one-of-join-memory-type","errorCode":null,"errorMessage":"memory_type must be one of: {', '.join(MEMORY_TYPES)}","messagePattern":"memory_type must be one of: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/memory/persistent.py","lineNumber":499,"sourceCode":"        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\n            # entry ends up on disk twice.\n            path = hierarchy.route_entry(memory_type, f\"{slug}.md\")","sourceCodeStart":481,"sourceCodeEnd":517,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/memory/persistent.py#L481-L517","documentation":"PersistentMemory.add only accepts memory_type values from the module-level MEMORY_TYPES whitelist; anything else is rejected before the record is stored. The allowed values are enumerated in the error message itself.","triggerScenarios":"Calling add(..., memory_type=\"note\") when the allowed set is e.g. observation/decision/outcome; passing a user-supplied or LLM-generated type string without validating it against MEMORY_TYPES.","commonSituations":"Prompt/tool schemas that allow free-form type fields, version drift where MEMORY_TYPES changed between releases, or casing mismatches like 'Observation'.","solutions":["Use one of the types listed in the error message (import MEMORY_TYPES to reference them)","Validate user/LLM input against MEMORY_TYPES before calling add","If a new type is genuinely needed, extend MEMORY_TYPES in agent/src/memory/persistent.py"],"exampleFix":"# before\nmem.add(name=..., memory_type=\"thought\", content=...)\n# after\nfrom agent.src.memory.persistent import MEMORY_TYPES\nassert memory_type in MEMORY_TYPES\nmem.add(name=..., memory_type=memory_type, content=...)","handlingStrategy":"type-guard","validationCode":"from agent.src.memory.persistent import MEMORY_TYPES\nmemory_type = (memory_type or '').strip().lower()\nif memory_type not in MEMORY_TYPES:\n    memory_type = 'observation'  # or reject explicitly\nmem.add(name=name, memory_type=memory_type, content=content)","typeGuard":"def is_valid_memory_type(t) -> bool:\n    return isinstance(t, str) and t.strip().lower() in MEMORY_TYPES","tryCatchPattern":"try:\n    mem.add(name=name, memory_type=memory_type, content=content)\nexcept ValueError as exc:\n    if 'memory_type must be one of' in str(exc):\n        mem.add(name=name, memory_type='observation', content=content)","preventionTips":["Restrict type fields in schemas/enums at the API boundary","Import MEMORY_TYPES and validate external input against it","Pin library versions when MEMORY_TYPES may change between releases"],"tags":["python","validation","enum","memory"],"backgroundTag":"invalid-enum-value","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}