affaan-m/ECC · error · ValueError
resolved SHA-256 required
Error message
resolved SHA-256 required
What it means
`_sha` validates that a value is a 64-character lowercase hexadecimal string (i.e. a resolved SHA-256 digest) before the tasteforge pipeline accepts it. This library throws it because downstream integrity checks (`expected_hash` comparisons in `_read_local`) are meaningless unless the caller supplies a fully resolved digest, not a placeholder, tag, partial hash, or non-string. If the value fails the regex `[a-f0-9]{64}`, the function refuses to proceed.
Solutions
- Compute the actual SHA-256 of the artifact (e.g. `hashlib.sha256(open(p,'rb').read()).hexdigest()`) and pass that value instead of a tag or short hash.
- Normalize the value: strip any `sha256:` prefix and call `.lower()` before passing it in.
- Check the string length with `len(value) == 64` and that it matches `^[a-f0-9]{64}$` before calling the API.
- If the value should be produced by an upstream step, fix that step to return a resolved digest rather than an unresolved reference.
Example fix
// before record["sha"] = "sha256:9F86D081884C7D659A2FEAA0C55AD015..." # prefixed, uppercase // after import hashlib digest = hashlib.sha256(artifact_bytes).hexdigest() # 64 lowercase hex chars record["sha"] = digest
Defensive patterns
Strategy: validation
Validate before calling
import re
REQUIRED_SHA_RE = re.compile(r"^[a-f0-9]{64}$")
def assert_resolved_sha(value):
if not isinstance(value, str) or not REQUIRED_SHA_RE.fullmatch(value):
raise ValueError(f"expected a resolved 64-char lowercase SHA-256, got {value!r}") Type guard
def is_resolved_sha256(value: object) -> bool:
return isinstance(value, str) and re.fullmatch(r"[a-f0-9]{64}", value) is not None Try / catch
try:
artifact = _artifact(record)
except ValueError as e:
if str(e) == "resolved SHA-256 required":
record["sha"] = hashlib.sha256(artifact_bytes).hexdigest()
artifact = _artifact(record)
else:
raise Prevention
- Always generate hashes with hashlib.hexdigest() — never hand-write or truncate digests.
- Keep a shared `compute_sha256(path)` helper so hash format is consistent everywhere.
- Strip `sha256:` prefixes and lowercase hex at the config/CLI boundary before values enter the pipeline.
- Validate hashes with a regex at every system boundary (config load, API input, request writer).
When it happens
Trigger: Calling `_artifact` (or any code path that funnels through `_sha`) with a value that is None, a non-string object, an uppercase hash, a 40-char SHA-1, a hex string of the wrong length, or a digest with a `sha256:` prefix.
Common situations: Passing a short commit SHA or container image tag instead of the full digest; copying a hash from a tool that uppercases hex; forgetting to compute the digest of an artifact before recording it in the application request; YAML/JSON config accidentally storing the hash as a number.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- approved hash must be lowercase SHA-256 hexadecimal
- receipt has an invalid source identity
- receipt source SHA-256 changed after generation
- rule lacks immutable reference evidence
- -32602
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/6625e82c38e2ba7b.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/integration.py:82
return n, d
def _range(value: Any, bounds: list[int] | None = None) -> list[int]:
if not isinstance(value, list) or len(value) != 2:
raise ValueError("range must contain two frame integers")
start, end = (_integer(v) for v in value)
if start >= end or (bounds is not None and (start < bounds[0] or end > bounds[1])):
raise ValueError("frame range is empty or outside its bounds")
return value
def _overlap(a: list[int], b: list[int]) -> bool:
return a[0] < b[1] and b[0] < a[1]
def _sha(value: Any) -> str:
if not isinstance(value, str) or not re.fullmatch(r"[a-f0-9]{64}", value):
raise ValueError("resolved SHA-256 required")
return value
def _identity(info: os.stat_result) -> tuple:
return (info.st_dev, info.st_ino, info.st_size, info.st_mtime_ns, info.st_ctime_ns)
def _artifact(record: Any, *, parse_json: bool = False) -> Any:
"""Read stable regular bytes without following links or hydrating cloud files."""
_object(record, {"path", "bytes", "sha256"})
return _read_local(_text(record["path"]), parse_json=parse_json,
expected_size=_integer(record["bytes"], 1),
expected_hash=_sha(record["sha256"]))
def _parent_fd(path: Path) -> int:
flags = os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK | os.O_DIRECTORY
parent = os.open(path.anchor, flags)View on GitHub (pinned to 8321021c54)