Stop the kernel from swallowing your syscall errors before they reach your logs
By Saket Jain Published Linux/Unix
Stop the kernel from swallowing your syscall errors before they reach your logs
Technical Briefing | 9/6/2026
You have likely been there. Your application is failing with an EPERM or ENOENT, but the logs tell you absolutely nothing. You check journald, check dmesg, and find nothing but silence. The problem is that most modern services just swallow these errors or log a vague message, leaving you to guess what path the kernel actually rejected. You don’t need more verbose logging from the app; you need to see exactly what the process is screaming at the kernel before the library hides it.
Why standard logging will never cut it here
Most developers wrap syscalls in layers of abstraction. By the time that code returns to your process, the original errno might be masked or logged as a generic error message. Using strace can help, but attaching it to a production process often introduces latency that causes race conditions to vanish. This is where eBPF tracing shows its worth. You can hook directly into the tracepoints that trigger when a syscall fails, capturing the PID, the command, and the specific return code without stopping the world.
bpftrace -e 'tracepoint:syscalls:sys_exit_open* /args->ret < 0/ { printf("%s (%d) failed to open %s with errno %d
", comm, pid, str(args->filename), -args->ret); }'
- The bpftrace command uses the sys_exit tracepoints to look at the return value of open calls in real-time
- It filters for negative returns indicating failure before the error code is lost
- This works across the entire system without requiring restarts or service modifications
Running this one-liner will light up your terminal the moment a process hits a wall. I have used this to catch phantom configuration reads where a process was looking for a file in a directory that a container runtime had blocked. It is one of those tools you keep in your back pocket for when everything seems to be failing, yet the logs remain suspiciously clean. The next time a service starts behaving like it is haunted, skip the log parsing and go straight to the syscall boundary.
