If you have ever installed TinyTeX on a relatively recent macOS system, you might have seen an admin password prompt pop up out of nowhere. What was TinyTeX doing behind the scenes? Well… honestly, something it shouldn’t have been doing. Issue #463 by r2evans gave me a thorough and well-deserved lecture on it, and I’ve finally fixed it in PR #489.
How we got here?
I should start with an apology. The old behavior was my fault, born from blindly following a practice I picked up from Homebrew years ago without keeping up with how things evolved.
In the early days of Homebrew, it would create symlinks to /usr/local/bin, and
back then (pre-Catalina, before 2019 or so) this directory was writable by
default on macOS. When Apple tightened its permissions so that /usr/local/bin
was no longer writable without sudo, Homebrew’s workaround was to ask users to
sudo chown the directory. I followed this approach blindly when I first built
TinyTeX’s PATH setup—adding a chown -R <user>:admin /usr/local/bin step via
osascript, followed by tlmgr path add to create symlinks from
/usr/local/bin/ into TinyTeX’s bin directory in the user’s home folder
(~/Library/TinyTeX/bin/*/).
What I failed to notice was that Homebrew itself eventually moved on: on Apple
Silicon Macs, it switched to /opt/homebrew, and the current Homebrew installer
creates /etc/paths.d/homebrew to register its bin path, relying on macOS’s
/usr/libexec/path_helper to incorporate it into PATH at shell startup. (It
also instructs users to add eval "$(brew shellenv)" to ~/.zprofile for the
full environment—PATH, MANPATH, INFOPATH, and a few Homebrew-specific
variables.) I kept using the old chown trick long after it had become outdated
and insecure. I should have updated TinyTeX’s approach at the same time. I’m
sorry it took this long.
What was the problem?
The old approach had two issues from a security standpoint:
-
Recursive
chownon unrelated files. Runningchown -R <user>:admin /usr/local/binrecursively changes the ownership of everything in that directory to the current user. Changing the ownership of files unrelated to TinyTeX is overreaching and hard to undo (you’d need to remember what the original owners were). -
Symlinks from a system directory into a user’s home folder. Running
tlmgr path addplaces symlinks from/usr/local/bin/into one particular user’s home directory. If that user’s home directory is unavailable or the TinyTeX installation moves, those symlinks become stale for anyone on the system who relies on/usr/local/bin. It also means a system-wide directory now depends on a single user’s private files, although I guess in most cases, you are the only user of your macOS.
r2evans put it plainly: “No R package should ever automatically/directly change permissions on a file/directory outside of the user’s home directory.” Hard to argue with that.
What’s the fix?
macOS provides /etc/paths.d/ as a way to register additional directories for
inclusion in PATH. Each file there contains one path per line, and
/usr/libexec/path_helper picks them up automatically when a shell starts.
Writing a single file there is narrowly scoped: it doesn’t touch any existing
binary, doesn’t change any permissions, and doesn’t create any cross-user
symlinks. It’s exactly what Homebrew does today with
/etc/paths.d/homebrew—and it’s what TinyTeX should have been doing all
along.
So the new behavior on macOS is:
-
If
/usr/local/binis not writable (the default on modern macOS): TinyTeX writes its bin directory path to/etc/paths.d/TinyTeXviasudo(still usingosascript, since/etc/paths.d/does require admin privileges to write). Nochown, no symlinks, no changes to any existing files. The old code that orchestrated thechown -Rdance is gone entirely. -
If
/usr/local/binis writable (meaning you previously went through the old setup): TinyTeX falls back to the oldtlmgr path addbehavior. I didn’t want to force existing users through anothersudoprompt for something they’ve already set up—but I’d encourage you to clean that up (see below).
The same logic applies in both the R functions (e.g., tlmgr_path()) and the
shell installer (install-bin-unix.sh). On Linux and Windows, nothing changes.
A few smaller improvements came along for the ride:
- Before running the
osascriptcommand (which triggers the password prompt), TinyTeX now prints a message telling you exactly whatsudocommand it’s about to run, so the password dialog no longer comes out of nowhere. - If the
sudooperation fails (e.g., you cancelled the password prompt), TinyTeX emits a message with the command you can run manually in your Terminal if you want. - The
.shinstaller gained a--no-pathflag to skipPATHmanipulation altogether, on any OS. Fortinytex::install_tinytex(), the existingadd_path = FALSEargument serves the same purpose.
What does this mean for you?
Fresh macOS installs: The next time you run tinytex::install_tinytex(),
you’ll see a message in the R console telling you the sudo command that is
about to run (writing TinyTeX’s bin path to /etc/paths.d/TinyTeX), followed by
the usual password dialog. No files in /usr/local/bin are touched.
Existing users—please consider cleaning up: If you previously ran through
the old setup, your /usr/local/bin is likely writable and TinyTeX is still
using the old tlmgr path add symlink approach. I’d encourage you to restore
the original ownership of /usr/local/bin and let TinyTeX switch over to the
new approach. Based on what I can tell from stat -f "%Su:%Sg" /usr/local on my
own machine, the command to restore it should be:
sudo chown root:wheel /usr/local/bin
(Note: some systems may have root:staff as the original group; you can check
with ls -la /usr/local to see what makes sense for your setup.)
That restores the directory itself, but our chown -R also changed the
ownership of files inside it—and we owe a note on those too. On my own Apple
Silicon machine, I can see two kinds of files in /usr/local/bin: tools placed
there by official macOS app installers (e.g., R and Rscript, which are
root:admin), and tools I installed myself (which are <user>:admin and were
not affected by TinyTeX’s chown). So the practical restoration for
installer-placed tools is sudo chown root:admin, not root:wheel. After
inspecting with ls -la /usr/local/bin, you can restore each affected file
individually, e.g.,
sudo chown root:admin /usr/local/bin/R /usr/local/bin/Rscript
After doing this, /usr/local/bin will no longer be writable, and on the next
call to tlmgr_path('add') TinyTeX will automatically write
/etc/paths.d/TinyTeX instead. You may also want to first remove the old
symlinks that tlmgr path add created:
tlmgr path remove
And then re-add TinyTeX’s path with the new approach:
if (packageVersion('tinytex') < '0.59')
install.packages('tinytex')
tinytex::tlmgr_path('add')
Again, my sincere apologies for letting this linger for so long. I should have
followed Homebrew’s lead when it moved to /etc/paths.d/ years ago. Better late
than never, I suppose.
My thanks to r2evans for the patient and detailed report. This change is part of tinytex v0.59, which just arrived CRAN last night.
If you run into any surprises with the new PATH setup on macOS, please file an issue. Thanks!
Donate
As a freelancer (currently working as a contractor) and a dad of three kids, I truly appreciate your donation to support my writing and open-source software development! Your contribution helps me cope with financial uncertainty better, so I can spend more time on producing high-quality content and software. You can make a donation through methods below.
-
Venmo:
@yihui_xie, or Zelle:xie@yihui.name -
Paypal
-
If you have a Paypal account, you can follow the link https://paypal.me/YihuiXie or find me on Paypal via my email
xie@yihui.name. Please choose the payment type as “Family and Friends” (instead of “Goods and Services”) to avoid extra fees. -
If you don’t have Paypal, you may donate through this link via your debit or credit card. Paypal will charge a fee on my side.
-
-
Other ways:
WeChat Pay (微信支付:谢益辉) Alipay (支付宝:谢益辉) 

When sending money, please be sure to add a note “gift” or “donation” if possible, so it won’t be treated as my taxable income but a genuine gift. Needless to say, donation is completely voluntary and I appreciate any amount you can give.
Please feel free to email me if you prefer a different way to give. Thank you very much!
I’ll give back a significant portion of the donations to the open-source community and charities. For the record, I received about $30,000 in total (before tax) in 2024-25, and gave back about $15,000 (after tax).