{"record":{"id":"57937e27d94ad800","repo":"affaan-m/ECC","slug":"name-must-be-a-nonempty-string","errorCode":null,"errorMessage":"{name} must be a nonempty string","messagePattern":"(.+?) must be a nonempty string","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/assets.py","lineNumber":25,"sourceCode":"\"\"\"\nfrom __future__ import annotations\n\nimport hashlib\nimport json\nimport os\nimport stat\nimport struct\nfrom pathlib import Path\nfrom typing import Any\n\nSCHEMA = 'tasteforge.assets.v1'\nMODALITIES = {'image', 'video', '3d_asset'}\nORIGINS = {'local_passthrough', 'external_result', 'recovered_unverified'}\n\n\ndef _text(value: Any, name: str) -> str:\n    if not isinstance(value, str) or not value.strip():\n        raise ValueError(f'{name} must be a nonempty string')\n    return value\n\n\ndef _path(value: Any, base: Path) -> Path:\n    raw = _text(str(value) if isinstance(value, Path) else value, 'path')\n    if '://' in raw or raw.startswith(('file:', 'http:', 'https:')):\n        raise ValueError('Only local filesystem paths are supported')\n    path = Path(raw).expanduser()\n    if not path.is_absolute():\n        path = base / path\n    # Check before resolving '..' to avoid hiding a symlink in the path.\n    for part in (path, *path.parents):\n        if part.is_symlink():\n            raise ValueError(f'Symlinks are not accepted: {part}')\n    return path.resolve()\n\n\ndef _fingerprint(path: Path, modality: str | None = None) -> dict[str, Any]:","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/assets.py#L7-L43","documentation":"The _text helper validates that a value is a nonempty, non-whitespace string and is used to validate names and paths across the tasteforge asset pipeline (_path, _assets, _provenance, _bundle, _taste). Any value that is None, a non-string (int, Path passed as name, etc.), or blank raises this ValueError with the given field name in the message.","triggerScenarios":"Calling ingest_assets/validate_assets/bundle/taste functions with a missing, None, or non-string name/path argument — e.g. name=None, name=123, or name=\"   \".","commonSituations":"Config dict missing the key so .get() yields None; passing a pathlib.Path where a name string is expected; blank values from environment variables or CLI flags that default to empty.","solutions":["Supply the missing value as a nonempty string.","Check the field name in the message to see which argument is wrong.","Coerce/convert values: str(value) for numbers, str(path) for Path objects.","Validate inputs with a schema or helper before calling the asset API."],"exampleFix":"// before\ningest_assets(sp, name=None, paths=[...])\n\n// after\ningest_assets(sp, name=\"pack-v1\", paths=[...])","handlingStrategy":"validation","validationCode":"def require_text(v, name):\n    if not isinstance(v, str) or not v.strip():\n        raise ValueError(f\"{name} must be a nonempty string\")\n    return v\n\nrequire_text(name, \"name\")","typeGuard":"def is_nonempty_str(v) -> bool:\n    return isinstance(v, str) and bool(v.strip())","tryCatchPattern":"try:\n    assets = ingest_assets(sp, name=name, paths=paths)\nexcept ValueError as e:\n    if \"must be a nonempty string\" in str(e):\n        raise UserInputError(f\"fix field in '{e}': supply a nonempty string\") from e\n    raise","preventionTips":["Validate all string inputs at the CLI/config boundary.","Replace .get() defaults of None with required-field checks.","Convert Path objects to str explicitly when an API expects names."],"tags":["input-validation","type-mismatch","empty-string"],"backgroundTag":"empty-required-field","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}