can1357/oh-my-pi · error · ArchiveError

ARJ member ' ' extracted to an unexpected size

Error message

ARJ member '${memberPath}' extracted to an unexpected size

What it means

This ArchiveError is thrown as a post-decompression invariant: the decompressor's output length does not equal the size declared in the member's local header. For stored members this is caught earlier, so this usually indicates a decoder produced fewer/more bytes than requested for methods 1–4, or the header's size field is wrong.

Solutions

  1. Test the archive with the official arj tool (arj t) to confirm corruption.
  2. Re-download or restore the archive from a good copy.
  3. Re-create the archive with a compliant tool.
  4. If the header size is genuinely wrong, patch the extraction to trust the decompressed length only when it matches, and skip members that fail.

Example fix

// before
const data = await member.read(member.size, member.path);
// after
try {
  const data = await member.read(member.size, member.path);
} catch (e) {
  if (e instanceof ArchiveError && e.message.includes('unexpected size')) {
    console.warn(`member ${member.path} size mismatch; archive header may be corrupt`);
    return null;
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const data = await member.read(size, path);
} catch (e) {
  if (e instanceof ArchiveError && e.message.includes('unexpected size')) {
    // archive header or compressed stream is corrupt; skip member
  } else throw e;
}

Prevention

When it happens

Trigger: Calling member.read(size, memberPath) where decompressLhStatic (methods 1–3) or decompressArjMethod4 (method 4) returns an output whose byteLength differs from size — typically because the packed stream is corrupt or the declared uncompressed size is wrong.

Common situations: Bit-rot or partial downloads corrupting compressed streams, archives written by buggy tools with wrong size fields, mixed-method archives assembled incorrectly.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/287ac7efdd06241b. Report an issue: GitHub.

Appendix: source

Thrown at packages/utils/src/ar/arj.ts:201

			case 2:
			case 3:
				output = decompressLhStatic(packed, size, 26_624, 5, 17, `ARJ method ${this.#method}`);
				break;
			case 4:
				output = decompressArjMethod4(packed, size);
				break;
			case 8:
			case 9:
				if (size !== 0 || packed.byteLength !== 0) {
					throw new ArchiveError(`ARJ member '${memberPath}' has invalid no-data method sizes`);
				}
				output = new Uint8Array(0);
				break;
			default:
				throw new ArchiveError(`ARJ member '${memberPath}' uses unsupported compression method ${this.#method}`);
		}
		if (output.byteLength !== size)
			throw new ArchiveError(`ARJ member '${memberPath}' extracted to an unexpected size`);
		if (this.#method !== 8 && crc32(output) !== this.#crc) {
			throw new ArchiveError(`ARJ member '${memberPath}' failed CRC32 verification`);
		}
		return output;
	}
}

function normalizeHostPath(rawPath: string, hostOs: number): string {
	let path = rawPath.replaceAll("\\", "/");
	if (hostOs === 1) path = path.replaceAll(">", "/");
	else if (hostOs === 4) path = path.replaceAll(":", "/");
	return path;
}

/** Probe whether bytes begin with a CRC-framed ARJ main header. */
export function sniffArj(bytes: Uint8Array): boolean {
	if (bytes.byteLength < 34 || bytes[0] !== ARJ_SIGNATURE_0 || bytes[1] !== ARJ_SIGNATURE_1) return false;
	const size = u16(bytes, 2);

View on GitHub (pinned to 9690622007)