This was quite an interesting error.
The cause of this error was that SHA-256 generated output containing a null byte.
The following error occurred only when trying to cache a specific URL: e.g. https://esm.sh/stable/react@18
Uncaught (in promise) TypeError: file name contained an unexpected NUL byte: lstat '<cache dir>/�g��E=m�Y:M���t ���-�Ƀ�c���j'
Here’s the minimal code to reproduce the issue:
import { cache } from "jsr:@denosaurs/[email protected]";
const ns = "";
const url = "https://esm.sh/stable/react@18";
const fs = await cache(url, undefined, ns);
console.log("cached: %o %o", fs.path, fs.meta);
The error occurred only when providing react@18
to esm.sh, so I assume this was an error I encountered probabilistically. Since I found it intriguing, I decided to investigate further.
It seems that, depending on the combination of SHA256 and input used in the process of computing the file name for cache storage, a NUL byte is unintentionally included.
Here's a version of the code with fewer dependencies:
// pick from https://github.com/denosaurs/cache/blob/83e4287694b0affe39bcad72f4cb7f99d3679057/file.ts#L125
async function hash(url: URL): Promise<string> {
const formatted = `${url.pathname}${url.search ? "?" + url.search : ""}`;
const encoder = new TextEncoder();
const data = encoder.encode(formatted);
const hash = await crypto.subtle.digest("SHA-256", data);
return new TextDecoder().decode(hash);
}
// await Deno.lstat("hello\0world"); // same error is occurred
const url = "https://esm.sh/stable/react@18";
const calculatedPath = await hash(new URL(url));
console.log("calculated path", calculatedPath);
console.log("has null byte?", calculatedPath.includes("\0")); // true
console.log(await Deno.lstat(calculatedPath)); // same error is occurred
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too