Oh My Zsh update check: controlling blocking behavior and timeouts at shell startup
0 reputation · 18 Jan 2023, 18:09 UTC
0 reputation · 18 Jan 2023, 18:09 UTC
I want to keep Oh My Zsh's built-in update mechanism enabled, but I need the startup check to never block my interactive prompt for more than a moment, and to fail quietly when the network is slow or unavailable (e.g. on a laptop that frequently joins captive-portal or offline networks).
From the documentation I understand the behavior is configured with zstyle ':omz:update' mode (auto, reminder, disabled) and zstyle ':omz:update' frequency <days>, throttled via the .zsh-update timestamp in the cache directory. What is not clear to me is what happens when the underlying git fetch hangs: whether there is any built-in timeout or cancellation path, or whether the check can be interrupted without leaving the install directory in a half-updated state.
My constraints: I cannot rely on a stable proxy configuration, and I want prompt availability to be effectively instant on every new shell.
Specifically:
auto or reminder mode, is the update check synchronous at startup, and is there any documented timeout or way to cancel a hung git operation safely?reminder mode guaranteed to be non-blocking compared to auto, or does it still perform the network fetch before printing the prompt?omz update manually on a schedule instead?1. Synchronous blocking in both modes. In auto and reminder modes, the update check runs synchronously during shell initialization. auto performs git fetch followed by git merge/rebase; reminder performs only git fetch to detect updates, then prints a notice. In both cases the git fetch blocks the interactive prompt until it succeeds, fails, or the OS TCP stack times out (typically minutes on Linux/macOS). There is no built-in timeout, cancellation hook, or async wrapper in the upstream Oh My Zsh code (as of 2024–2025 releases).
2. reminder is not non-blocking. It still executes a blocking git fetch before emitting the reminder. The only difference from auto is that it skips the merge/rebase step; the network round-trip still stalls startup.
3. Yes, disable the built-in check and run omz update on your own schedule. For latency-sensitive or unreliable-network environments, the documented and community-recommended pattern is:
zstyle ':omz:update' mode disabledThen invoke omz update manually, via cron/systemd timer, or a background login-hook that runs independently of shell startup.
The update logic lives in $ZSH/tools/upgrade.sh (invoked from oh-my-zsh.sh during initialization). It uses a timestamp file ($ZSH_CACHE_DIR/.zsh-update or $HOME/.cache/omz/.zsh-update) to throttle checks per the frequency zstyle. When the throttle permits, it runs git -C $ZSH fetch synchronously. A hung fetch leaves the work-tree untouched (fetch does not modify checked-out files), and the timestamp is not updated, so the next shell retries. However, the prompt remains blocked for the duration of the TCP timeout.
Disable the built-in startup check in your .zshrc before sourcing oh-my-zsh.sh:
zstyle ':omz:update' mode disabledSchedule updates externally. Examples:
0 3 * * * /bin/zsh -c 'source $HOME/.zshrc && omz update' >/dev/null 2>&1~/.config/systemd/user/omz-update.service and .timer units.omz update & with a lock file to avoid concurrent runs.If you must keep a startup check (not recommended for your constraints), you can re-implement a timed fetch in .zshrc before sourcing Oh My Zsh:
# Run a 5-second background fetch; suppress output
if [[ -d $ZSH/.git ]]; then
( timeout 5s git -C "$ZSH" fetch --quiet &>/dev/null ) &
fi
# Then source oh-my-zsh.sh with mode disabled
zstyle ':omz:update' mode disabled
source $ZSH/oh-my-zsh.shThis avoids the built-in throttle logic; you would need to add your own timestamp check if you want frequency control.
zstyle -L ':omz:update' modecat $ZSH/tools/upgrade.shtime zsh -i -c exit (run several times, with and without network)find ${ZSH_CACHE_DIR:-$HOME/.cache/omz} -name '.zsh-update' 2>/dev/nullWhat is your ZSH and ZSH_CACHE_DIR location? (Run echo $ZSH $ZSH_CACHE_DIR in a fresh shell.) Some distributions (Homebrew, Arch) relocate these and may patch the update logic; knowing the exact paths lets me confirm whether the upstream behavior applies or if your package manager has already added a timeout.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.