i Too Many Levels of Linking in `zsh` · Dark Matter Industries

Too Many Levels of Linking in `zsh`

One unexpected error that I have been receiving when sourcing a configuration script in zsh (e.g. source .muttrc) is “too many levels of linking”.

That stumped me for some time. I eventually figured out that the issue had to do with using variables when symbolically linking those config scripts.

Let me explain.

Like most people these days I work on several computers. In my case they are all macOS/Darwin machines. Hence I need to sync most of my configuration scripts across those machines to make my environments familiar, and maintain my multitude of key bindings, when I move from one to the other.

Many people use Github for this purpose, but since I do not have any cross-platform requirements, the simplest was to build it off the built-in iCloud sync’ing capabilities of my machines. Plus it is secure.

So the first thing I did was to use zsh’s built in “dot directory” variable, $ZDOTDIR. In order to accommodate launching zsh as an interactive but not login shell, e.g. launching it from within a bash shell, I decided to use .zshenv to define $ZDOTDIR (although .zshrc would work):

% cat ~/.zshenv
ZDOTDIR=$HOME/Documents/dotfiles

Notice I am already using an environmental variable $HOME in the definition of another environmental variable $ZDOTDIR

Now, the “Documents” directory in macOS is synchronized to iCloud (if you enable it), so any config scripts that live in the dotfiles subdirectory would sync to all of my Darwin machines.

But now, when I symbolically link a config script in that dotfile directory to where an executing program or shell expects it to go, e.g.:

% ln -s $ZDOTDIR/muttrc $HOME/.muttrc

the symbolic link is created with no issues, however, I get the “too many levels of linking” error when trying to launch that program later.

It took me some time to get to the bottom of this, since my config files are full of variables that could potentially cause that problem. So to save you countless hours of troubleshooting, I am giving you the solution: just don’t use the $ZDOTDIR variable when creating the link:

% ln -s ~/Documents/dotfiles/muttrc $HOME/.muttrc

Alternatively, use the explicit path when defining $ZDOTDIR in the first place.

I haven’t yet experimented whether using the system-wide tilde ~ alias in place of $HOME in the $ZDOTDIR definition would also work.


Note to self: see if this is also an issue in bash.