{"record":{"id":"80d91a94ceddc301","repo":"MemPalace/mempalace","slug":"field-name-must-be-a-non-empty-string","errorCode":null,"errorMessage":"{field_name} must be a non-empty string","messagePattern":"(.+?) must be a non-empty string","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mempalace/config.py","lineNumber":79,"sourceCode":"    The same rule is applied by ``init`` when persisting `topics_by_wing`\n    and when writing `mempalace.yaml`, so the miner's lookup matches at\n    mine time regardless of the source dirname.\n\n    Leading/trailing separators are stripped so a path-encoded dirname like\n    ``-home-user-proj`` yields ``home_user_proj`` rather than a leading-\n    underscore slug that ``sanitize_name`` (and thus the MCP write tools)\n    would reject.\n    \"\"\"\n    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","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/config.py#L61-L97","documentation":"Raised by sanitize_name() when the wing/room/entity name is not a string, or is a string that is empty or whitespace-only after potential stripping. Names become directory/collection identifiers, so a blank name would create an unusable path. Every MCP write tool and most CLI write paths route names through this validator.","triggerScenarios":"Calling a write tool or CLI command with name=None, name=123 (non-string), name=\"\" or name=\"   \" — e.g. a script passing an unset environment variable or an LLM tool call omitting the name field so it arrives as empty.","commonSituations":"Unset shell variable expanding to empty string ($NAME with NAME undefined); MCP client sending null for an omitted optional-looking field; whitespace-only name pasted from a form; programmatic callers passing an int id.","solutions":["Supply a real, non-empty name for the field identified in the message (field_name tells you which argument)","In calling code, check the value before the call: if not (isinstance(n, str) and n.strip())","Fix shell scripts to fail fast on unset variables (set -u / ${NAME:?})"],"exampleFix":"# before\nwing = os.environ.get(\"WING\", \"\")   # empty when unset\ncreate_wing(wing)\n\n# after\nwing = os.environ[\"WING\"]           # fails fast, or validate first\nif not wing.strip(): raise SystemExit(\"WING name required\")\ncreate_wing(wing)","handlingStrategy":"type-guard","validationCode":"# Before any name-taking call:\nif not isinstance(name, str) or not name.strip():\n    raise SystemExit(\"name must be a non-empty string\")","typeGuard":"def is_valid_name(value) -> bool:\n    return isinstance(value, str) and bool(value.strip())","tryCatchPattern":"try:\n    safe = sanitize_name(name, \"wing\")\nexcept ValueError as exc:\n    if \"non-empty\" in str(exc):\n        name = fallback_name  # e.g. \"unnamed\"\n    else:\n        raise","preventionTips":["Fail fast on unset shell variables (set -u) in scripts that pass names","Check MCP tool arguments for missing/None name fields before sending","Validate names at your app boundary, not inside storage code"],"tags":["validation","names","mempalace"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}