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

  1. 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.
  2. Normalize the value: strip any `sha256:` prefix and call `.lower()` before passing it in.
  3. Check the string length with `len(value) == 64` and that it matches `^[a-f0-9]{64}$` before calling the API.
  4. 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

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


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)