{"record":{"id":"a6cc497f514b9c2a","repo":"cocoindex-io/cocoindex","slug":"invalid-dtype-specification-dtype-spec","errorCode":null,"errorMessage":"Invalid dtype specification: {dtype_spec}","messagePattern":"Invalid dtype specification: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/_internal/datatype.py","lineNumber":38,"sourceCode":"try:\n    import pydantic\n\n    PYDANTIC_AVAILABLE = True\nexcept ImportError:\n    PYDANTIC_AVAILABLE = False\n\n# PEP 695 ``type`` aliases (``typing.TypeAliasType``) only exist on Python 3.12+.\n# numpy >= 2.5 defines ``numpy.typing.NDArray`` as one, so we must transparently\n# unwrap it to reach the underlying ``numpy.ndarray[...]`` type.\n_TypeAliasType = getattr(typing, \"TypeAliasType\", None)\n\n\ndef extract_ndarray_elem_dtype(ndarray_type: Any) -> Any:\n    args = typing.get_args(ndarray_type)\n    _, dtype_spec = args\n    dtype_args = typing.get_args(dtype_spec)\n    if not dtype_args:\n        raise ValueError(f\"Invalid dtype specification: {dtype_spec}\")\n    return dtype_args[0]\n\n\ndef is_numpy_number_type(t: type) -> bool:\n    return isinstance(t, type) and issubclass(t, (np.integer, np.floating))\n\n\ndef is_namedtuple_type(t: type) -> bool:\n    return isinstance(t, type) and issubclass(t, tuple) and hasattr(t, \"_fields\")\n\n\ndef is_pydantic_model(t: Any) -> bool:\n    \"\"\"Check if a type is a Pydantic model.\"\"\"\n    if not PYDANTIC_AVAILABLE or not isinstance(t, type):\n        return False\n    try:\n        return issubclass(t, pydantic.BaseModel)\n    except TypeError:","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/_internal/datatype.py#L20-L56","documentation":"When analyzing an NDArray annotation, extract_ndarray_elem_dtype expects numpy.ndarray[Shape, DType] where DType itself is a parametrized numpy dtype (e.g. np.dtype[np.float32]). If the dtype argument has no type parameters (bare np.dtype, plain np.float64 used directly, or Any), the element dtype cannot be extracted and ValueError is raised.","triggerScenarios":"Annotating a field/argument as np.ndarray[Any, np.dtype] (bare dtype), np.ndarray[Any, np.float64] (non-parametrized scalar), or np.ndarray (missing args entirely, giving an unpack failure), then calling analyze_type_info on the annotation.","commonSituations":"Writing Vector[...] embeddings with sloppy numpy typing; code written for numpy<2.5 where NDArray alias handling differed; using `npt.NDArray` without a dtype parameter.","solutions":["Annotate as np.ndarray[Any, np.dtype[np.float32]] (or npt.NDArray[np.float32]) with a parametrized dtype","Use cocoindex's Vector type helper with a concrete scalar type instead of raw ndarray","Check the annotation with typing.get_args before passing it to analysis in custom tooling"],"exampleFix":"// before\nvec: np.ndarray[Any, np.dtype]  # bare dtype\n\n// after\nimport numpy.typing as npt\nvec: npt.NDArray[np.float32]","handlingStrategy":"validation","validationCode":"import typing\ndef has_parametrized_dtype(t) -> bool:\n    args = typing.get_args(t)\n    return len(args) == 2 and bool(typing.get_args(args[1]))","typeGuard":null,"tryCatchPattern":"try:\n    info = coco.analyze_type_info(annotation)\nexcept ValueError as e:\n    if \"Invalid dtype\" in str(e):\n        annotation = fix_dtype(annotation)\n    else:\n        raise","preventionTips":["Always write npt.NDArray[np.float32] instead of bare NDArray or ndarray[Any, np.dtype]","Prefer cocoindex's Vector[T] helper over raw ndarray annotations","Add a mypy/ruff check that flags unparametrized numpy generics"],"tags":["python","numpy","typing","dtype"],"backgroundTag":"invalid-argument-format","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}