{"record":{"id":"20f60af0f4a7e3b6","repo":"apache/beam","slug":"spec-type-not-found-in-spec","errorCode":null,"errorMessage":"Spec type not found in {spec}","messagePattern":"Spec type not found in (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/ml/anomaly/specifiable.py","lineNumber":169,"sourceCode":"  @classmethod\n  def spec_type(cls) -> str:\n    pass\n\n  @classmethod\n  def from_spec(cls,\n                spec: Spec,\n                _run_init: bool = True) -> Union[Self, type[Self]]:\n    \"\"\"Generate a `Specifiable` subclass object based on a spec.\n\n    Args:\n      spec: the specification of a `Specifiable` subclass object\n      _run_init: whether to call `__init__` or not for the initial instantiation\n\n    Returns:\n      Self: the `Specifiable` subclass object\n    \"\"\"\n    if spec.type is None:\n      raise ValueError(f\"Spec type not found in {spec}\")\n\n    subspace = _spec_type_to_subspace(spec.type)\n    subclass: type[Self] = _KNOWN_SPECIFIABLE[subspace].get(spec.type, None)\n\n    if subclass is None:\n      raise ValueError(f\"Unknown spec type '{spec.type}' in {spec}\")\n\n    if spec.config is None:\n      # when functions or classes are used as arguments, we won't try to\n      # create an instance.\n      return subclass\n\n    kwargs = {\n        k: _specifiable_from_spec_helper(v, _run_init)\n        for k, v in spec.config.items()\n    }\n\n    if _run_init:","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/ml/anomaly/specifiable.py#L151-L187","documentation":"Specifiable.from_spec instantiates a Specifiable subclass from a Spec dataclass. If the Spec's .type field is None, the lookup cannot proceed and a ValueError is raised. This is a required-field check before resolving the type to a registered subclass.","triggerScenarios":"Constructing a Spec() without passing type (e.g. Spec(config=...) or relying on the default None) and then passing it to from_spec; programmatically built specs where the type assignment was skipped.","commonSituations":"Specs deserialized from config/JSON missing the 'type' key; dataclass defaults leaving type unset; code paths that build a Spec incrementally and forget to set type.","solutions":["Set Spec.type to a registered specifiable type string, e.g. Spec(type='ZScore', config=...).","Validate the spec before calling from_spec: assert spec.type is not None.","Fix the deserialization/config source so the 'type' field is included.","Check the spec's repr in the error message to see which fields were actually populated."],"exampleFix":"// before\nspec = Spec(type=None, config={\"threshold\": 3})\n// after\nspec = Spec(type=\"ZScore\", config={\"threshold\": 3})","handlingStrategy":"validation","validationCode":"if spec.type is None:\n    raise ValueError(f\"Spec.type required before from_spec: {spec}\")","typeGuard":"def has_type(spec): return getattr(spec, 'type', None) is not None","tryCatchPattern":"try:\n    obj = Specifiable.from_spec(spec)\nexcept ValueError as e:\n    logger.error(\"incomplete spec: %s\", e)\n    raise","preventionTips":["Always pass type explicitly to Spec()","Validate deserialized spec dicts contain a 'type' key","Avoid relying on dataclass defaults for required fields"],"tags":["python","anomaly-detection","spec","missing-field"],"backgroundTag":"missing-required-argument","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}