can1357/oh-my-pi · error · Error
Refusing to download onto a non-regular file: ${absolutePath
Error message
Refusing to download onto a non-regular file: ${absolutePath} What it means
After opening the destination without following symlinks, the writer stats the handle and refuses if the inode is not a regular file. Downloads may only land on plain files, never directories, devices, sockets, or FIFOs that slipped past the open flags. This is an explicit integrity guard around overwriting existing content.
Source
Thrown at packages/coding-agent/src/cursor.ts:193
async function writeWithoutFollowingLinks(absolutePath: string, payload: string | Buffer): Promise<void> {
await fs.promises.mkdir(path.dirname(absolutePath), { recursive: true });
const handle = await fs.promises
.open(
absolutePath,
fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK,
)
.catch((error: NodeJS.ErrnoException) => {
// A readerless FIFO. Reported as the refusal it is, rather than the
// bare "no such device or address" the errno spells out.
if (error.code === "ENXIO") {
throw new Error(`Refusing to download onto a special file: ${absolutePath}`);
}
throw error;
});
try {
const stat = await handle.stat();
if (!stat.isFile()) {
throw new Error(`Refusing to download onto a non-regular file: ${absolutePath}`);
}
if (stat.nlink > 1) {
throw new Error(
`Refusing to download onto a file with ${stat.nlink} hard links, which would overwrite its other names: ${absolutePath}`,
);
}
await handle.truncate(0);
await handle.writeFile(payload);
} finally {
await handle.close();
}
}
function createToolResultMessage(
toolCallId: string,
toolName: string,
result: AgentToolResult<unknown>,
isError: boolean,View on GitHub (pinned to 9690622007)
Solutions
- Choose a download path that is a regular file (or does not exist yet).
- If a directory occupies the name, remove or rename the directory first (`rm -r <path>`).
- Do not target device or socket nodes; pick a path under your workspace.
Example fix
// before
{ downloadPath: "/tmp/out" } // /tmp/out is a directory
// after
{ downloadPath: "/tmp/out/report.json" } Defensive patterns
Strategy: validation
Validate before calling
const s = await stat(downloadPath).catch(() => null);
if (s && !s.isFile()) throw new Error(`${downloadPath} exists and is not a regular file`); Type guard
function isPlainFile(s: import("node:fs").Stats | undefined): boolean {
return !!s && s.isFile();
} Try / catch
try {
await downloadResource(res, downloadPath);
} catch (e) {
if (String(e.message).startsWith("Refusing to download onto a non-regular file")) {
// choose a different destination path
} else throw e;
} Prevention
- Ensure the destination name doesn't collide with an existing directory or socket.
- Download into a dedicated directory that only contains regular files.
- Stat the destination before writing when reusing paths.
When it happens
Trigger: The downloadPath resolves to an existing directory, socket, block/character device, or another special inode (a case the ENXIO open guard doesn't cover, e.g. a FIFO with a reader or a directory opened with O_CREAT which fails differently).
Common situations: A resource name collides with a directory of the same name; pointing the download at /dev/null or a unix socket; a stale symlink-target directory.
Related errors
- ENXIO
- Refusing to download onto a file with ${stat.nlink} hard lin
- The managed-skills root is a symlink; refusing to operate ou
- Managed skill "${name}" SKILL.md is a symlink; refusing to o
- Managed skill "${name}" resolves through a symlink; refusing
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/32b491a41c50c809.
Report an issue: GitHub.