heygen-com/hyperframes · error

[s3Transport] expected lowercase SHA-256 digest, got ${JSON.

Error message

[s3Transport] expected lowercase SHA-256 digest, got ${JSON.stringify(value)}

What it means

Thrown by assertSha256, a private guard called at the top of both uploadContentAddressedFileToS3 and downloadS3ObjectToFileVerified, when the expectedSha256 argument does not match the strict lowercase-hex 64-character pattern /^[a-f0-9]{64}$/. The library uses the digest both as a CAS key and as an S3 ChecksumSHA256 header, so any malformed value (uppercase, base64, truncated, prefixed) would produce a corrupt content-addressed key or a signature mismatch downstream. Failing early prevents a bad object from landing in the immutable store.

Source

Thrown at packages/aws-lambda/src/s3Transport.ts:210

  } finally {
    // A failed conditional request may reject before consuming the stream.
    // Explicit teardown avoids retaining the source descriptor on a warm
    // Lambda planner.
    body.destroy();
  }
}

export async function sha256File(path: string): Promise<string> {
  const hash = createHash("sha256");
  for await (const chunk of createReadStream(path)) {
    hash.update(chunk as Buffer);
  }
  return hash.digest("hex");
}

function assertSha256(value: string): void {
  if (!/^[a-f0-9]{64}$/.test(value)) {
    throw new Error(
      `[s3Transport] expected lowercase SHA-256 digest, got ${JSON.stringify(value)}`,
    );
  }
}

type ContentAddressedObjectState = "missing" | "matching" | "conflict";

async function inspectContentAddressedObject(
  client: S3Client,
  bucket: string,
  key: string,
  expectedSize: number,
  expectedSha256: string,
): Promise<ContentAddressedObjectState> {
  try {
    const existing = await client.send(
      new HeadObjectCommand({ Bucket: bucket, Key: key, ChecksumMode: "ENABLED" }),
    );

View on GitHub (pinned to c2996c8626)

Solutions

  1. Normalize the digest to lowercase hex before the call: digest.toLowerCase().
  2. If the source is base64, convert it: Buffer.from(b64, 'base64').toString('hex').
  3. Strip any algorithm prefix (e.g. 'sha256:') before passing.
  4. Verify the digest is exactly 64 chars with /[a-f0-9]{64}/ before constructing the call.

Example fix

// before
const sha = checksumBase64; // S3 returns base64
await uploadContentAddressedFileToS3(client, path, uri, sha);

// after
const sha = Buffer.from(checksumBase64, 'base64').toString('hex');
await uploadContentAddressedFileToS3(client, path, uri, sha);
Defensive patterns

Strategy: validation

Validate before calling

function normalizeSha256(value: string): string {
  let v = value;
  if (v.startsWith('sha256:')) v = v.slice('sha256:'.length);
  // base64 -> hex if it looks like base64 (44 chars, ends with =)
  if (/^[A-Za-z0-9+/]{43}=$/.test(v)) v = Buffer.from(v, 'base64').toString('hex');
  return v.toLowerCase();
}
function assertValidSha256(value: string): void {
  if (!/^[a-f0-9]{64}$/.test(value)) throw new Error(`bad sha256: ${value}`);
}

Type guard

const isLowerHexSha256 = (v: unknown): v is string =>
  typeof v === 'string' && /^[a-f0-9]{64}$/.test(v);

Try / catch

try {
  await uploadContentAddressedFileToS3(client, path, uri, normalizeSha256(sha));
} catch (err) {
  if (err instanceof Error && err.message.includes('expected lowercase SHA-256')) {
    throw new Error(`digest normalization failed for input: ${sha}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing a digest in uppercase hex (e.g. from a tool that uppercases), a base64-encoded checksum (S3's native ChecksumSHA256 wire format), a truncated 32-char digest, or a value with a 'sha256:' prefix. Any caller of uploadContentAddressedFileToS3 or downloadS3ObjectToFileVerified whose digest source differs from crypto.createHash('sha256').digest('hex').

Common situations: Interfacing with a system that emits base64 digests (AWS SDK ChecksumSHA256 is base64); copying a digest from a git log or UI that uppercases; a manifest schema that stores 'sha256:abcd…'; passing the raw hash Buffer instead of its hex string.

Related errors


AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12). Data as JSON: /api/errors/00957d228ee67fc2. Report an issue: GitHub.