CLI crashes with sandbox error when spawned as a subprocess on Linux (AppArmor userns restriction)

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 scriptsobsidian 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

  1. 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-sandbox to the Electron flags during initialization. This is the approach many Electron-based CLIs take.
  2. 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.
  3. 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).

You BR is not clear to me

You did not provide the output of “show debug info command”

  1. Run obsidian with obsidian --no-sandbox
  2. Run your script

Does it work?

You can also try to append --no-sandbox to every command

Another way to repro this is to run claude and ask it to run the obsidian CLI. It finds the CLI but any time it invokes the CLI it crashes and I get a modal saying “Obsidian quit unexpectedly.”

simply running ! obsidian inside of claude is enough to show this. I can’t seem to upload a .txt to show the crash report but this is running on macOS. Here’s the top snippet:

Triggered by Thread: 0, Dispatch Queue: com.apple.main-thread

Exception Type:    EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000010
Exception Codes:   0x0000000000000001, 0x0000000000000010

Termination Reason:  Namespace SIGNAL, Code 11, Segmentation fault: 11
Terminating Process: exc handler [97723]


VM Region Info: 0x10 is not in any region.  Bytes before following region: 4297949168
      REGION TYPE                    START - END         [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  
      __TEXT                      1002d8000-1002dc000    [   16K] r-x/r-x SM=COW  /Applications/Obsidian.app/Contents/MacOS/Obsidian