{"record":{"id":"80473b32542704db","repo":"HKUDS/Vibe-Trading","slug":"modelartifact-input-hash-must-be-a-64-character-sh","errorCode":null,"errorMessage":"ModelArtifact.input_hash must be a 64-character sha256 hex digest, got {self.input_hash!r}","messagePattern":"ModelArtifact\\.input_hash must be a 64-character sha256 hex digest, got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/valuation/artifact.py","lineNumber":263,"sourceCode":"    excluded: tuple[str, ...]\n    warnings: tuple[str, ...]\n\n    def __post_init__(self) -> None:\n        \"\"\"Check the artifact's own invariants.\n\n        Raises:\n            ValueError: If ``model_name`` is not one of :data:`_MODEL_NAMES`,\n                or ``input_hash`` is not a 64-character hex sha256 digest.\n        \"\"\"\n        if self.model_name not in _MODEL_NAMES:\n            raise ValueError(\n                f\"ModelArtifact.model_name must be one of {_MODEL_NAMES}, \"\n                f\"got {self.model_name!r}\"\n            )\n        if len(self.input_hash) != 64 or any(\n            c not in \"0123456789abcdef\" for c in self.input_hash\n        ):\n            raise ValueError(\n                f\"ModelArtifact.input_hash must be a 64-character sha256 hex \"\n                f\"digest, got {self.input_hash!r}\"\n            )\n\n\n@dataclass(frozen=True)\nclass FieldChange:\n    \"\"\"One field that differs between two artifacts' inputs or outputs.\n\n    Attributes:\n        path: The dotted/bracket path that changed.\n        old: The baseline artifact's value at ``path``.\n        new: The updated artifact's value at ``path``.\n        delta: ``new - old`` when both are numbers (and neither is a\n            ``bool``); ``None`` otherwise (e.g. a string or boolean field, or\n            a field that changed type).\n    \"\"\"\n","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/valuation/artifact.py#L245-L281","documentation":"ModelArtifact validates that input_hash is exactly a 64-character lowercase hex string — the shape of a sha256 digest produced by compute_input_hash. Anything else (short hash, uppercase, 'md5', None) is rejected so artifacts can be reliably keyed and compared by hash.","triggerScenarios":"ModelArtifact(input_hash=hashlib.md5(...).hexdigest(), ...) (32 chars); passing an uppercase digest, a truncated hash, or a placeholder string; passing None and hitting the length check behavior.","commonSituations":"Swapping hash algorithms during a refactor; hand-building artifacts in tests with dummy hashes like 'abc'; feeding a non-hash id field.","solutions":["Use the project's compute_input_hash(...) to produce the digest.","If hashing yourself: hashlib.sha256(...).hexdigest() gives exactly 64 lowercase hex chars.","Never truncate or re-case the digest before storing it."],"exampleFix":"// before\nModelArtifact(input_hash=hashlib.md5(payload).hexdigest(), ...)\n// after\nfrom quantlib.valuation.artifact import compute_input_hash\nModelArtifact(input_hash=compute_input_hash(inputs), ...)","handlingStrategy":"type-guard","validationCode":"import re\nassert isinstance(input_hash, str) and re.fullmatch(r\"[0-9a-f]{64}\", input_hash), \\\n    f\"input_hash must be 64-char sha256 hex, got {input_hash!r}\"","typeGuard":"import re\ndef is_sha256_hex(s) -> bool:\n    return isinstance(s, str) and re.fullmatch(r\"[0-9a-f]{64}\", s) is not None","tryCatchPattern":null,"preventionTips":["Always generate hashes with compute_input_hash or hashlib.sha256(...).hexdigest().","Never upper-case, truncate, or substitute hash algorithms."],"tags":["python","sha256","hash-validation","artifact"],"backgroundTag":"invalid-hash-format","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}