Summary
The Obsidian CLI works correctly when launched interactively in a terminal, but crashes with a fatal Chromium sandbox error when invoked programmatically as a child process (e.g. via child_process.exec() in Node.js, a shell script, or any tool that forks a subprocess).
This makes the CLI unusable for the primary automation use cases it is designed for: scripting, MCP servers, and integration with external tools.
Environment
- Obsidian version: 1.12.4 (early access installer)
- OS: Linux (Ubuntu 24.04 with AppArmor)
- CLI enabled: Yes (Settings → General → Command line interface)
Steps to Reproduce
Works (interactive):
obsidian
# → TUI launches, connects to running Obsidian instance ✅
Fails (subprocess):
# From a shell script or any tool that forks a child process:
obsidian bases
obsidian version
obsidian search query="test"
# → Any non-interactive CLI command
Also fails from Node.js:
const { exec } = require("child_process");
exec("obsidian bases", (err, stdout, stderr) => {
// crashes before producing any output
});
Error Output
[PID:FATAL:content/browser/zygote_host/zygote_host_impl_linux.cc:128] No usable sandbox!
If you are running on Ubuntu 23.10+ or another Linux distro that has disabled
unprivileged user namespaces with AppArmor, see
https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md.
Otherwise see https://chromium.googlesource.com/chromium/src/+/main/docs/linux/suid_sandbox_development.md
Trace/breakpoint trap (core dumped)
Exit code: 133
Root Cause
On Ubuntu 23.10+ (and other distributions with AppArmor’s userns restrictions enabled), Chromium/Electron requires unprivileged user namespaces for sandboxing. When Obsidian is launched interactively from a user terminal, the process context allows this. When spawned as a child process from another application, the AppArmor policy for the parent process restricts namespace creation, causing a fatal crash before Electron can initialize.
The --no-sandbox flag exists as a workaround for Chromium, but it cannot be passed to the Obsidian binary by tools invoking the CLI because they can’t control what flags the binary accepts.
Expected Behavior
obsidian <command> should execute successfully when called from any subprocess context, not just from a user’s interactive terminal session.
Impact
This blocks the CLI’s primary automation use cases on Linux:
- Shell scripts —
obsidian search query="..."in a bash script - MCP servers — tools that wrap the Obsidian CLI as an MCP server for LLM integration (e.g. reading vault content, managing notes programmatically)
- IDE integrations — editors or coding assistants spawning Obsidian CLI commands
- CI/CD pipelines — any automated workflow running on Linux
The CLI documentation explicitly advertises scripting and automation as core use cases. This makes the feature non-functional on the most common Linux developer configurations.
Possible Solutions
- Detect non-interactive mode and use
--no-sandbox— if the CLI detects it is not attached to a TTY (i.e. running as a subprocess), it could automatically add--no-sandboxto the Electron flags during initialization. This is the approach many Electron-based CLIs take. - Ship a thin CLI wrapper binary — instead of symlinking to the Electron app directly, ship a separate lightweight binary (not Electron-based) that communicates with the running Obsidian instance over a socket/IPC. This would eliminate the sandbox dependency entirely for CLI invocations.
- AppArmor profile — ship an AppArmor profile that grants the necessary permissions for the Obsidian binary when invoked as a subprocess. This would be the safest option from a security standpoint.
Option 2 is likely the most robust long-term solution, and would also improve CLI performance significantly (no Electron startup overhead).
