can1357/oh-my-pi · error · ArchiveError

Invalid compress (.Z) output limit

Error message

Invalid compress (.Z) output limit

What it means

decode() validates its maxOutput parameter before touching the stream: it must be a non-negative safe integer. This is an argument-validation error — the caller passed an invalid bound (negative, NaN, non-integer, or > Number.MAX_SAFE_INTEGER), not a data problem.

Source

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

		if (!Number.isSafeInteger(needed) || needed > this.#limit) {
			throw new ArchiveError(`Compress (.Z) output exceeds the ${this.#limit}-byte limit`);
		}
		if (needed <= this.#bytes.byteLength) {
			return;
		}
		let capacity = Math.max(needed, Math.min(this.#limit, Math.max(64, this.#bytes.byteLength * 2)));
		if (capacity > this.#limit) {
			capacity = this.#limit;
		}
		const grown = new Uint8Array(capacity);
		grown.set(this.#bytes.subarray(0, this.#length));
		this.#bytes = grown;
	}
}

function decode(bytes: Uint8Array, maxOutput: number): Uint8Array {
	if (!Number.isSafeInteger(maxOutput) || maxOutput < 0) {
		throw new ArchiveError("Invalid compress (.Z) output limit");
	}
	if (bytes.byteLength < 3) {
		throw new ArchiveError("Truncated compress (.Z) header");
	}
	if (bytes[0] !== 0x1f || bytes[1] !== 0x9d) {
		throw new ArchiveError("Invalid compress (.Z) header");
	}

	const flags = bytes[2]!;
	if ((flags & 0x60) !== 0) {
		throw new ArchiveError("Unsupported compress (.Z) header flags");
	}
	const maxBits = flags & 0x1f;
	if (maxBits < MIN_BITS || maxBits > MAX_BITS) {
		throw new ArchiveError(`Invalid compress (.Z) maximum code width ${maxBits}`);
	}
	const blockMode = (flags & 0x80) !== 0;
	const dictionaryLimit = 2 ** maxBits;

View on GitHub (pinned to 9690622007)

Solutions

  1. Validate maxOutput at the call site: a non-negative safe integer before calling lzwDecompress.
  2. Fix the source of the value — check parseInt/Number conversions for NaN and config parsing for missing fields.
  3. Provide a sensible default (e.g. 256MB) when the configured limit is absent.
  4. Guard with Number.isSafeInteger(maxOutput) && maxOutput >= 0 before calling.

Example fix

// before: unparsed config
const max = Number(config.maxZOutput);
lzwDecompress(bytes, max);
// after
const max = Number(config.maxZOutput);
if (!Number.isSafeInteger(max) || max < 0) throw new Error("Invalid maxZOutput config");
lzwDecompress(bytes, max);
Defensive patterns

Strategy: validation

Validate before calling

function assertValidMaxOutput(maxOutput: number): void {
  if (!Number.isSafeInteger(maxOutput) || maxOutput < 0) {
    throw new Error(`maxOutput must be a non-negative safe integer, got ${maxOutput}`);
  }
}

Type guard

function isValidMaxOutput(v: unknown): v is number {
  return typeof v === "number" && Number.isSafeInteger(v) && v >= 0;
}

Try / catch

try {
  return lzwDecompress(bytes, maxOutput);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("output limit")) {
    throw new Error(`Bad maxOutput argument: ${maxOutput}`, { cause: err });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling lzwDecompress(data, maxOutput) with maxOutput = -1, NaN, a float, undefined coerced oddly, or an unsafe integer computed from bad metadata.

Common situations: maxOutput read from a config file or env var without parsing validation; a NaN from a failed parseInt/Number conversion; arithmetic overflow producing Infinity before the call.

Related errors


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