Linux launcher drops application arguments before spawning the main process

Author: ManuelGilCreated Sep 11, 2026Updated Sep 11, 2026

Summary

I found a reproducible Linux launcher issue where application arguments reach the Electrobun launcher but are not forwarded to the application process.

This affects ordinary application arguments in general, not only file paths or MIME-associated files.

I initially found this while integrating a real Electrobun application on Linux, but I reproduced the behavior independently across several argument types so the result does not depend on that application.

I would appreciate confirmation of whether dropping non-launcher arguments is intentional. If it is not intentional, this appears to be a small but important launcher issue because applications cannot receive normal command-line arguments when started through the packaged Linux launcher.

Environment

  • OS: Ubuntu 24.04.5 LTS
  • Architecture: x86_64
  • Desktop: GNOME
  • Display server: Wayland
  • Electrobun: 2.0.1 linux-x64
  • Electrobun core SHA256: 29da550b3cb30c0b868b6155aa35b791548baa044f97118951e1c7a413c95307
  • Electrobun launcher SHA256: eac32746ea0fc765f8fa5e6d9685cd76c8e172ff312671c862fd26cb3db2b3fa
  • Electrobun launcher size: 243896 bytes
  • Cottontail: 0.5.0, revision e5660061
  • Bun toolchain: 1.4.0
  • Test date: 2026-09-11

The launcher binary used by the packaged application was byte-identical to the Electrobun 2.0.1 release launcher from the Hutch release cache.

The tested launcher therefore was not a modified downstream launcher.

Minimal reproduction

Run a packaged Electrobun Linux application launcher with an ordinary argument:

./MyApp/bin/launcher /tmp/probe/test.txt

The launcher process receives the argument.

For example, /proc/<launcher-pid>/cmdline contains:

.../app/bin/launcher
/tmp/probe/test.txt

The child process does not receive it.

The child process is started as:

.../app/bin/bun .../Resources/main.js

rather than:

.../app/bin/bun .../Resources/main.js /tmp/probe/test.txt

In the tested application, the resulting process.argv was equivalent to:

[bun, main.js]

with no application argument present.

The same result can be observed directly from /proc/<child-pid>/cmdline.

Argument matrix

I tested the launcher with different kinds of arguments to determine whether this was related to MIME types, file extensions, paths, or a particular number of arguments.

Case User arguments Launcher receives Main process receives
test.txt 1 yes 0
test.md 1 yes 0
test.bin 1 yes 0
README, no extension 1 yes 0
directory 1 yes 0
directory containing files 1 yes 0
three files 3 yes 0
directory plus file 2 yes 0
path containing spaces 1 yes 0
hello-world, not a path 1 yes 0

The three-file test used:

test.txt test.md test.json

All three arguments reached the launcher, but none reached the child process.

The directory tests also reached the launcher and were dropped before the child process was created.

The hello-world test is important because it is not a file path, directory, MIME type, or file association. It is just an ordinary argument. It was also dropped.

This does not appear to be MIME related

The same behavior was observed for:

  • text files
  • Markdown files
  • binary files
  • files without extensions
  • directories
  • arbitrary string arguments

No MIME database was changed during the tests.

This suggests the problem occurs below MIME association and below desktop file association handling.

The desktop entry path is not where the argument is lost

The original downstream use case involves a Linux desktop entry using:

Exec=myapp %F

The %F field represents one or more local paths as separate arguments.

The downstream wrapper used for the test is:

exec /opt/myapp/bin/launcher "$@"

The wrapper was verified to preserve the arguments exactly.

The launcher then receives the expected arguments.

The loss happens after the launcher receives them and before the application main process starts.

So the observed chain is:

desktop or shell
    |
    v
wrapper
    |
    | arguments preserved
    v
Electrobun launcher
    |
    | arguments received
    |
    | arguments dropped
    v
main process

Launcher source analysis

In the current Electrobun source, package/src/launcher/main.zig constructs the child argument vector as:

zig
argv = &[_][]const u8{ runtime_path, main_script };

This creates a child argv containing only the runtime and main script.

The launcher does receive the original arguments and stores them as launcher_args.

The launcher also has its own recognized options. Inspection of the 2.0.1 launcher binary found:

--automation
--bootstrap-install
--delete-data
--quiet
--uninstall

This suggests that there is already a conceptual distinction between arguments owned by the launcher and arguments intended for the application.

The issue is that the remaining arguments are not forwarded to the child process.

For example, unrecognized arguments such as:

--help
--version

also start the application normally and do not appear in the child argv.

I am not assuming this behavior is accidental. I would like to confirm whether dropping all non-launcher arguments is intentional.

Expected behavior

For a normal application argument such as:

./MyApp/bin/launcher /tmp/probe/test.txt

I would expect the application process to receive the argument in the same order and multiplicity, for example:

bun Resources/main.js /tmp/probe/test.txt

Likewise:

./MyApp/bin/launcher file1.txt file2.txt

would result in the application receiving:

file1.txt
file2.txt

as two separate arguments.

Arguments containing spaces should remain a single argument.

I am not trying to prescribe the exact implementation. In particular, I would be happy to follow whatever argument forwarding contract Electrobun considers correct.

Why this matters on Linux

Normal Linux desktop integration commonly needs an application to receive paths when launched from a desktop entry, file manager, xdg-open, or another application.

A desktop entry can provide paths through %F, but those paths are only useful if the packaged application launcher preserves them.

This also affects non-file use cases because the test with the plain string:

hello-world

is dropped as well.

So the observed behavior appears broader than file opening:

Linux launcher does not forward ordinary application arguments

rather than:

Markdown files cannot be opened

Relation to file associations

The current Electrobun documentation states that file associations are currently packaged on macOS and that Windows and Linux URL schemes and file associations are not yet implemented.

I am not relying on the file association API for this report.

The issue here is lower level: when an application is invoked with an ordinary command-line argument on Linux, the launcher receives that argument but does not pass it to the application process.

The expected Linux mechanism could therefore be independent of Electrobun's macOS open-url behavior.

Current upstream status

I also checked the current upstream source rather than assuming that 2.0.1 was simply outdated.

The 2.0.2 beta line is active, and the relevant launcher source in current main still constructs the child argv with only:

zig
runtime_path
main_script

I could not find an existing issue or pull request specifically covering Linux launcher application argument forwarding.

I searched for issues and pull requests involving:

  • argv
  • arguments
  • launcher
  • launcher arguments
  • file association
  • open-url
  • deep link
  • desktop
  • %F

No matching issue was found.

Downstream use case

This was first discovered while packaging Fulvid, an Electrobun application for Linux.

Fulvid already has an application-side argument adapter that:

  • reads application arguments;
  • resolves paths;
  • distinguishes files and directories;
  • passes them to a single host-side external-open handler.

That code is currently unreachable for packaged Linux launches because the arguments disappear in the Electrobun launcher before the application main process starts.

We deliberately did not work around this with an environment variable, socket, daemon, localhost listener, or another side channel. Such a workaround would introduce a second authority for document opening and would not solve the underlying launcher behavior for other Electrobun applications.

The Fulvid use case is therefore provided only as a real downstream example, not as a requirement for the proposed solution.

Possible direction

I do not want to prescribe an implementation without knowing the intended Electrobun argument contract.

If the intended behavior is to forward application arguments, one possible direction would be:

  1. consume arguments owned by the launcher;
  2. keep launcher-specific behavior unchanged;
  3. forward the remaining application arguments to the main process;
  4. preserve order, multiplicity, and argument boundaries.

For example:

launcher --launcher-option file1.txt file2.txt

could result in the application receiving:

file1.txt
file2.txt

if that matches the intended Electrobun contract.

If instead Electrobun intentionally keeps the launcher argument namespace closed and does not forward arbitrary arguments, I would appreciate guidance on the supported Linux mechanism for applications that need to receive arguments from the desktop or another process.

Questions

Could you please confirm:

  1. Is dropping ordinary non-launcher arguments intentional?
  2. If it is intentional, what is the supported mechanism for a Linux application to receive arguments such as file paths?
  3. If forwarding is intended, should launcher-owned flags be consumed while all remaining arguments are passed to the main process?
  4. Is there an existing argument forwarding mechanism that I have missed?
  5. Should Linux use argv for this purpose while macOS continues to use open-url, or is a common cross-platform mechanism planned?

Thanks for taking the time to look at this. I wanted to provide a minimal, reproducible case with several argument types rather than report this only as a file association problem from one downstream application.