schollz/croc · error · Error

Hash algorithm "${info.HashAlgorithm}" is not supported

Error message

Hash algorithm "${info.HashAlgorithm}" is not supported

What it means

validateSenderInfo() accepts only the xxhash algorithm. If the offer's HashAlgorithm field is present and set to anything else (e.g. 'sha256', 'md5'), the client cannot verify chunk integrity because its wasm pipeline only implements xxhash, so the transfer is refused before any data flows.

Source

Thrown at web/src/protocol/metadata.ts:66

export function normalizeOutgoingFileName(value: string) {
  // Go's unicode.IsPrint accepts ASCII space but rejects the other Unicode
  // separator characters commonly inserted into filenames by macOS.
  const compatible = value.replace(/\p{Z}+/gu, " ");
  return normalizeFilePath(".", compatible).name;
}

function finiteSize(file: WireFileInfo) {
  const size = file.s ?? 0;
  if (!Number.isSafeInteger(size) || size < 0) {
    throw new Error(`Invalid file size for ${file.n ?? "unnamed file"}`);
  }
  return size;
}

export function validateSenderInfo(info: SenderInfoWire): TransferOffer {
  if (info.SendingText) throw new Error("Text transfers are not supported yet");
  if (info.HashAlgorithm && info.HashAlgorithm !== "xxhash") {
    throw new Error(`Hash algorithm "${info.HashAlgorithm}" is not supported`);
  }

  const destinations = new Set<string>();
  const files: OfferedFile[] = [];
  let totalSize = 0;
  for (const wire of info.FilesToTransfer ?? []) {
    if (wire.sy) throw new Error("Symlink transfers are not supported in the browser");
    const normalized = normalizeFilePath(wire.fr ?? ".", wire.n ?? "");
    if (destinations.has(normalized.path)) {
      throw new Error(`Duplicate destination path: ${normalized.path}`);
    }
    destinations.add(normalized.path);
    const size = finiteSize(wire);
    totalSize += size;
    if (!Number.isSafeInteger(totalSize)) throw new Error("Transfer size is too large");
    files.push({
      ...normalized,
      size,

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Have the sender use a croc version whose HashAlgorithm is xxhash (the stock croc default).
  2. If a custom algorithm is mandatory for your deployment, implement it in the wasm verification pipeline first, then widen the check in validateSenderInfo.
  3. As a receiver, catch this error and tell the peer to update/downgrade to a compatible croc build.
Defensive patterns

Strategy: type-guard

Validate before calling

function isSupportedHash(info: SenderInfoWire): boolean {
  return !info.HashAlgorithm || info.HashAlgorithm === "xxhash";
}

Type guard

function hasCompatibleHash(info: SenderInfoWire): info is SenderInfoWire & { HashAlgorithm?: "xxhash" } {
  return !info.HashAlgorithm || info.HashAlgorithm === "xxhash";
}

Try / catch

try {
  const offer = validateSenderInfo(info);
} catch (error) {
  if (error instanceof Error && /Hash algorithm/.test(error.message)) {
    notifyUser("sender uses an unsupported hash; ask them to use stock croc (xxhash)");
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: A croc build or fork that negotiates a non-xxhash HashAlgorithm sends an offer to this client; or hand-crafted SenderInfoWire with HashAlgorithm: 'sha256'. An absent or 'xxhash' value passes.

Common situations: Peer running a modified/newer croc that switched the default hash algorithm; forked protocol variants; test fixtures copied from a different croc version; security scanners checking the strictness of algorithm negotiation.

Related errors


AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15). Data as JSON: /api/errors/dbb3c600f3eba527. Report an issue: GitHub.