EACCES: preserve the runtime's symbolic error and syscall
EACCES identifies a denied access request, not a universal repair command. Preserve the library's error code, syscall and access mode. The same Windows file-open restriction can become Python EACCES or Node EPERM; numeric errno, Win32 codes and translated text belong to different error contracts. Match this output from operating-system, then continue with sourced, read-only checks.
- Confidence
- high
- Platforms
- linux · macos · windows
- Verified
- 2026-09-30
Signature matched locally
EACCES: preserve the runtime's symbolic error and syscallOneLiners matches this pattern in your browser. Your pasted output is not stored or indexed.
What usually produces this signal
- The process cannot use the selected file/directory in the requested mode, even though a metadata lookup succeeds.
- An existence/access precheck is treated as authorization for a later operation; intervening changes and Windows ACL checks make that conclusion unsafe.
- A wrapper's symbolic errno is confused with another runtime's or a native Windows code, hiding the original operation and platform.
Collect evidence before changing the system
Read structured errors from the actual failing I/O handler
// Existing Node failure handler, not a newly replayed write.
console.log({ platform: process.platform, node: process.versions.node,
code: error.code, syscall: error.syscall });
// Existing Python failure handler instead:
// print({'errno': error.errno, 'code': errno.errorcode.get(error.errno),
// 'winerror': getattr(error, 'winerror', None)})
// Do not print error.path, argv, file contents or the whole environment.Expected signal: Use the captured code and syscall with the actual runtime. Our Windows Node write-open returns EPERM while CPython reports errno13/EACCES for the same owned ReadOnly file. A missing field stays unknown; never relabel EPERM as EACCES just to match an expected phrase.
A code is evidence about this attempted operation, not proof of missing administrator rights. On Linux also distinguish execute, path traversal and parent creation requirements. Do not normalize distinct errors to a generic permission message in incident logs.
Treat one target's metadata as context, not permission to write
// One already-approved target; inspect metadata without modifying it.
import { lstat } from 'node:fs/promises';
try {
const s = await lstat(approvedPath);
console.log({ file: s.isFile(), directory: s.isDirectory(), symlink: s.isSymbolicLink() });
} catch (error) { console.log({ code: error.code }); }
// Handle the real operation's error at its call site. Do NOT add
// fs.access(..., W_OK) as a guarantee before open/write/unlink.Expected signal: A file=True snapshot and a failed write-open can both be correct. lstat inspects a symlink itself, not its resolved target. Node fs.access does not validate Windows ACLs, and a precheck cannot eliminate a check/use race.
Metadata errors must not be silently converted to 'missing'. Record the intended path's role privately and the original access request; do not follow an unknown link or change ACLs because an existence/access check looks favorable.
Check the input against the result
Input and result
# Native Windows, one owned ReadOnly temporary file, same user and path.
# Node22: lstat(path), then open(path, 'r+'); retain its actual code/syscall.
# CPython: open(path, 'r+b'); map the captured errno through errno.errorcode.
# Verify the known fixture bytes; restore ONLY our original attribute
# and confirm the same Node write-open/close succeeds without writing data.exists=True write_open=EPERM syscall=open
python_code=EACCES errno=13
original_preserved=True same_identity_write_open=readyThese are actual results from two runtimes, not a fabricated Node EACCES. The comparison demonstrates why a Linux/Python symbolic name cannot stand in for a captured Windows/Node event. No ACL or protected production file was used, and the positive control changed neither identity nor elevation.
Correct only the demonstrated cause
Repair the specific configuration/path/access mode established by the original I/O evidence. Handle failed operations and preserve their structured error instead of relying on an existence/access precheck. Any policy or grant change belongs to the resource owner and must be limited to the evidenced need.
Verify: The intended operation succeeds under the original identity/runtime with the correct target, while negative access cases retain their real codes and do not corrupt data. Confirm that error handling releases handles and does not automatically retry a potentially mutating operation.
Stop if: A code's runtime/operation is unknown, the target is an untrusted symlink, a proposed fix modifies shared ACLs or credentials, or success is inferred only from fs.access/stat rather than the intended operation.