can1357/oh-my-pi · error · ArchiveError

Archive file '${normalizedPath}' has no readable storage

Error message

Archive file '${normalizedPath}' has no readable storage

What it means

ArchiveError thrown by ArchiveReader.readFile() when the entry exists and is a file, but entry.storage is unset — the archive records the member but its content bytes are not available/readable through the reader. The library refuses to proceed instead of silently returning empty data.

Source

Thrown at packages/utils/src/ar/reader.ts:145

	async readFile(subPath: string): Promise<ExtractedArchiveFile> {
		const normalizedPath = normalizeArchiveLookupPath(subPath);
		if (!normalizedPath) {
			throw new ArchiveError("Archive file path is required");
		}

		const resolvedPath = resolveArchiveLinkPath(this.#entries, normalizedPath, this.limits.maxLinkDepth);
		if (resolvedPath === "") {
			throw new ArchiveError(`Archive path '${normalizedPath}' is a directory`);
		}
		const entry = this.#entries.get(resolvedPath);
		if (!entry) {
			throw new ArchiveError(`Archive file '${normalizedPath}' not found`);
		}
		if (entry.isDirectory) {
			throw new ArchiveError(`Archive path '${normalizedPath}' is a directory`);
		}
		if (!entry.storage) {
			throw new ArchiveError(`Archive file '${normalizedPath}' has no readable storage`);
		}
		assertArchiveMemberSize(entry.size, normalizedPath, this.limits);

		if (entry.storage.type === "link") {
			throwUnreadableArchiveLink(entry.storage.targetPath, normalizedPath);
		}
		const bytes = await entry.storage.source.read(entry.size, normalizedPath);
		return {
			path: normalizedPath,
			isDirectory: false,
			size: entry.size,
			mtimeMs: entry.mtimeMs,
			mode: entry.mode,
			bytes,
		};
	}
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-verify the archive file is complete and uncorrupted (compare checksums)
  2. Inspect the entry via the reader's listing API to confirm storage type before reading
  3. If the archive is a link-type or unsupported storage, handle those members separately
  4. Regenerate or re-download the archive

Example fix

// before
const data = await reader.readFile(name);
// after
try {
  const data = await reader.readFile(name);
} catch (err) {
  if (err instanceof ArchiveError && /no readable storage/.test(err.message)) {
    // treat member as unreadable metadata-only entry
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

const entry = reader.getEntry?.(name);
if (entry && !entry.isDirectory && !entry.storage) {
  throw new Error(`member '${name}' has no readable storage`);
}

Type guard

function hasStorage(e: { storage?: unknown } | undefined): e is { storage: object } {
  return e !== undefined && e.storage != null;
}

Try / catch

try {
  const data = await reader.readFile(name);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('no readable storage')) {
    // treat as metadata-only member; fall back to re-fetching the archive
  } else throw err;
}

Prevention

When it happens

Trigger: Calling reader.readFile(path) on a member whose parsed entry has no storage record (e.g. archive format stores metadata-only entries or the storage was not attached during parsing).

Common situations: Reading members from unusual or partially supported archive variants where the parser recognized the entry name but not its data section; corrupted or non-standard archives.

Related errors


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