#1610·direnv

stdlib: skip absent user-library globs when globbing is disabled

Author: pmarreckCreated Aug 17, 2026Updated Aug 17, 2026

Summary

When Bash pathname expansion is disabled (set -f / noglob), direnv's global-library loop attempts to source a literal file named *.sh when ~/.config/direnv/lib/ is absent or empty. This emits a spurious error even though the project environment loads successfully.

Reproduction

bash
tmp=$(mktemp -d "$TMPDIR/direnv-noglob-proof.XXXXXX")
mkdir -p "$tmp/home" "$tmp/project" "$tmp/config/direnv"
printf "%s\n" "export DIRENV_NOGLOB_PROOF=1" > "$tmp/project/.envrc"

HOME="$tmp/home" XDG_CONFIG_HOME="$tmp/config" DIRENV_CONFIG="$tmp/config/direnv" \
  direnv allow "$tmp/project/.envrc"

(
  cd "$tmp/project"
  env HOME="$tmp/home" XDG_CONFIG_HOME="$tmp/config" DIRENV_CONFIG="$tmp/config/direnv" \
    SHELLOPTS=braceexpand:hashall:interactive-comments:noglob \
    direnv export bash >/dev/null
)

Expected: no stderr output related to optional global library files.

Actual (exit status remains zero):

environment:1428: /tmp/.../config/direnv/lib/*.sh: No such file or directory

The relevant stdlib code is:

bash
for lib in "$direnv_config_dir/lib/"*.sh; do
  # shellcheck disable=SC1090
  source "$lib"
done

nullglob handles an unmatched pattern only while pathname expansion is enabled. With noglob, the pattern remains literal and the loop body runs once.

Proposed fix

Guard each candidate before sourcing it:

bash
for lib in "$direnv_config_dir/lib/"*.sh; do
  [[ -f $lib ]] || continue
  # shellcheck disable=SC1090
  source "$lib"
done

This preserves the intended behavior for existing libraries and makes the optional directory truly optional regardless of the caller's Bash globbing option. A regression test should run direnv with noglob and a missing or empty config lib directory, then assert that no missing-file diagnostic is emitted.