can1357/oh-my-pi · error · ArchiveError

${error instanceof Error ? error.message : String(error)}

Error message

${error instanceof Error ? error.message : String(error)}

What it means

lzwDecompress wraps the internal decode() and normalizes any non-ArchiveError exception (RangeError from typed arrays, TypeErrors, etc.) into an ArchiveError carrying the original message. Hitting this wrapper means an unexpected runtime exception escaped decode() — usually caused by invalid argument types rather than corrupt stream content (which already throws typed ArchiveErrors).

Source

Thrown at packages/utils/src/ar/codecs/lzw.ts:189

			needsPreviousSuffix = false;
		}
	}
}

/** Return whether bytes begin with the ncompress `.Z` magic number. */
export function isCompressZ(bytes: Uint8Array): boolean {
	return bytes.byteLength >= 2 && bytes[0] === 0x1f && bytes[1] === 0x9d;
}

/** Decompress an ncompress `.Z` stream while enforcing a hard output bound. */
export async function lzwDecompress(bytes: Uint8Array, maxOutput: number): Promise<Uint8Array> {
	try {
		return decode(bytes, maxOutput);
	} catch (error) {
		if (error instanceof ArchiveError) {
			throw error;
		}
		throw new ArchiveError(error instanceof Error ? error.message : String(error));
	}
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Validate arguments before calling: ensure bytes is a Uint8Array/Buffer and maxOutput is a positive safe integer.
  2. Read the wrapped message in the ArchiveError — it names the underlying cause; fix that specific problem.
  3. If maxOutput comes from config/user input, clamp/parse it (Number.parseInt + Number.isSafeInteger check).
  4. For persistent unexpected errors, reproduce with a minimal input and report; decode() is expected to throw typed ArchiveErrors for stream problems only.

Example fix

// before
const limit = config.maxOutput; // possibly "10485760" or undefined
await lzwDecompress(input, limit);
// after
const limit = Number(config.maxOutput);
if (!Number.isSafeInteger(limit) || limit <= 0) throw new Error("bad maxOutput");
await lzwDecompress(new Uint8Array(input), limit);
Defensive patterns

Strategy: validation

Validate before calling

function assertDecompressArgs(bytes: unknown, maxOutput: unknown): asserts bytes is Uint8Array {
  if (!(bytes instanceof Uint8Array)) throw new TypeError("bytes must be a Uint8Array/Buffer");
  if (!Number.isSafeInteger(maxOutput) || (maxOutput as number) < 0) throw new TypeError("maxOutput must be a non-negative safe integer");
}

Type guard

function isDecompressInput(v: unknown): v is { bytes: Uint8Array; maxOutput: number } {
  return typeof v === "object" && v !== null && v.bytes instanceof Uint8Array && Number.isSafeInteger(v.maxOutput) && v.maxOutput >= 0;
}

Try / catch

try {
  return await lzwDecompress(bytes, maxOutput);
} catch (e) {
  if (e instanceof ArchiveError && !(e.message.startsWith("Invalid compress") || e.message.includes("Corrupt") || e.message.includes("Truncated"))) {
    // wrapped unexpected error: log the underlying message for diagnosis
    console.error("unexpected LZW failure:", e.message);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling lzwDecompress with a non-integer or negative maxOutput (NaN, undefined coerced, Infinity), passing a non-Uint8Array view (Buffer is fine, but a DataView or plain array is not), or a typed-array operation throwing inside decode (e.g. output limit so large that allocation fails).

Common situations: maxOutput accidentally left undefined or parsed from config as a string; passing options object fields of the wrong type; wiring the function into generic decompress dispatch that routes formats it cannot handle; OOM-scale maxOutput values.

Related errors


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