Skip to content

zsh does not expand a tilde in env VAR=~/path, and opencode creates the literal directory

This is a finding

Something I found or learned, or a discovery that cost time once: cheap by design, and true of a moment rather than in general.

Two innocuous behaviours compose into a confusing one. opencode run --model <anything> failed with UnknownError: Unexpected server error for every model I tried, including one I was sitting in a working session of, which read as a provider outage or a rejected credential. It was neither.

The command was:

env OPENCODE_CONFIG_DIR=~/.config/opencode/profiles/github-copilot opencode run ...

zsh expands a tilde after = only in a real assignment, or with MAGIC_EQUAL_SUBST set. In env VAR=~/path the whole thing is an ordinary command argument, so the tilde survives as a literal character and the variable holds the relative path ~/.config/opencode/.... The same tilde in export VAR=~/path, or in the command-prefix form VAR=~/path opencode ..., expands normally - which is why most of my commands that day worked and three did not.

opencode then creates a missing config directory rather than failing, so the relative path produced a real directory named ~ under the current working directory:

./~/.config/opencode/profiles/github-copilot/

It contained no opencode.json, so the session enabled no providers - my base config sets enabled_providers: [] deliberately, to fail closed. The session therefore had no model to reach and reported it as a server error rather than as a missing provider. opencode had also populated it with a node_modules tree, 276 directories, which is what made it visible at all: it showed up in a recursive diff against a backup taken an hour earlier.

How to tell

Two cheap checks, both faster than debugging the error:

  • ls -d './~' in the directory you ran from. A literal tilde directory is never intentional.
  • Print the variable as the child sees it: env VAR=~/x sh -c 'echo "$VAR"' shows ~/x, whilst VAR=~/x sh -c 'echo "$VAR"' shows the expanded path.

Use "$HOME/..." rather than a tilde whenever the assignment is an argument to another command. It expands in every shell and in every position, which a tilde does not.

The general shape is worth more than the specific bug: a tool that silently creates a missing config directory converts a typo into a plausible-looking empty configuration, and every error after that describes the empty configuration rather than the typo. The symptom appears at the first operation that needed a setting, arbitrarily far from the cause.

Observed with opencode 1.18.33 under zsh.

The following pages link to this page: