{"record":{"id":"a716136f68999f24","repo":"MemPalace/mempalace","slug":"field-name-contains-invalid-path-characters","errorCode":null,"errorMessage":"{field_name} contains invalid path characters","messagePattern":"(.+?) contains invalid path characters","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mempalace/config.py","lineNumber":88,"sourceCode":"    return name.lower().replace(\" \", \"_\").replace(\"-\", \"_\").strip(\"_\")\n\n\ndef sanitize_name(value: str, field_name: str = \"name\") -> str:\n    \"\"\"Validate and sanitize a wing/room/entity name.\n\n    Raises ValueError if the name is invalid.\n    \"\"\"\n    if not isinstance(value, str) or not value.strip():\n        raise ValueError(f\"{field_name} must be a non-empty string\")\n\n    value = value.strip()\n\n    if len(value) > MAX_NAME_LENGTH:\n        raise ValueError(f\"{field_name} exceeds maximum length of {MAX_NAME_LENGTH} characters\")\n\n    # Block path traversal\n    if \"..\" in value or \"/\" in value or \"\\\\\" in value:\n        raise ValueError(f\"{field_name} contains invalid path characters\")\n\n    # Block null bytes\n    if \"\\x00\" in value:\n        raise ValueError(f\"{field_name} contains null bytes\")\n\n    # Enforce safe character set\n    if not _SAFE_NAME_RE.match(value):\n        raise ValueError(f\"{field_name} contains invalid characters\")\n\n    return value\n\n\ndef sanitize_kg_value(value: str, field_name: str = \"value\") -> str:\n    \"\"\"Validate a knowledge-graph entity name (subject or object).\n\n    More permissive than sanitize_name — allows punctuation like commas,\n    colons, and parentheses that are common in natural-language KG values.\n    Only blocks null bytes and over-length strings.","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/config.py#L70-L106","documentation":"Raised by sanitize_name() when the name contains '..', '/', or '\\\\'. Wing and room names map onto filesystem directory names and collection ids, so path separators or traversal sequences could escape the palace directory or corrupt the layout; they are rejected outright rather than escaped.","triggerScenarios":"Passing a name like \"../palace_backup\", \"docs/notes\", \"C:\\\\wings\", or any string containing a slash, backslash, or '..' — commonly from user-typed paths or file-derived names passed unmodified.","commonSituations":"Users supplying a relative path instead of a bare name; deriving names from file paths without taking only the basename; Windows-style names with backslashes; LLM tool calls echoing a path the user mentioned.","solutions":["Pass only the final path segment: use Path(p).name or os.path.basename(p) to derive the name","Replace separators with underscores if the hierarchical look matters: name.replace(\"/\", \"_\")","Never construct storage paths yourself — pass bare names and let the library build paths"],"exampleFix":"# before\ncreate_room(\"projects/mempalace/2026-08-14\")\n\n# after\ncreate_room(\"projects_mempalace_2026-08-14\")","handlingStrategy":"validation","validationCode":"# Derive names from paths safely before any call:\nfrom pathlib import Path\nname = Path(user_path).name          # final segment only\nif \"..\" in name:\n    raise SystemExit(\"invalid name\")","typeGuard":"def is_path_safe_name(value: str) -> bool:\n    return isinstance(value, str) and not any(t in value for t in (\"..\", \"/\", \"\\\\\")) and bool(value.strip())","tryCatchPattern":"try:\n    safe = sanitize_name(name)\nexcept ValueError as exc:\n    if \"invalid path characters\" in str(exc):\n        safe = sanitize_name(name.replace(\"/\", \"_\").replace(\"\\\\\", \"_\"))\n    else:\n        raise","preventionTips":["Never pass user-typed paths as wing/room names; take Path(p).name","Replace separators with underscores when hierarchy matters visually","Let the library build storage paths from bare names"],"tags":["validation","path-traversal","security","names","mempalace"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}