openai/codex · warning · anyhow::Error

Snapshot output missing marker {marker}

Error message

Snapshot output missing marker {marker}

What it means

Snapshot scripts source the user's rcfile first (e.g. the zsh script sources $ZDOTDIR/.zshrc or $HOME/.zshrc) and only then emit the literal line '# Snapshot file'. strip_snapshot_preamble searches the captured stdout for that marker and bails if it is absent. The error therefore means the shell ran but never reached the marker print — startup side effects swallowed, redirected, or terminated output before the marker.

Source

Thrown at codex-rs/core/src/shell_snapshot.rs:240

    let snapshot_path = output_path.display();
    fs::write(output_path, snapshot)
        .await
        .with_context(|| format!("Failed to write snapshot to {snapshot_path}"))?;

    Ok(())
}

async fn capture_snapshot(shell: &Shell, cwd: &AbsolutePathBuf) -> Result<String> {
    let shell_type = shell.shell_type;
    let script = snapshot_script(shell_type)
        .ok_or_else(|| anyhow!("Shell snapshotting is not yet supported for {shell_type:?}"))?;
    run_shell_script(shell, &script, cwd).await
}

fn strip_snapshot_preamble(snapshot: &str) -> Result<String> {
    let marker = "# Snapshot file";
    let Some(start) = snapshot.find(marker) else {
        bail!("Snapshot output missing marker {marker}");
    };

    Ok(snapshot[start..].to_string())
}

async fn validate_snapshot(
    shell: &Shell,
    snapshot_path: &AbsolutePathBuf,
    cwd: &AbsolutePathBuf,
) -> Result<()> {
    let snapshot_path_display = snapshot_path.display();
    let script = format!("set -e; . \"{snapshot_path_display}\"");
    run_script_with_timeout(
        shell,
        &script,
        SNAPSHOT_TIMEOUT,
        /*use_login_shell*/ false,
        cwd,

View on GitHub (pinned to 339751715c)

Solutions

  1. Reproduce manually: run the printed login-shell command with stdin closed and check stdout for '# Snapshot file' — the offending rcfile line will be obvious
  2. Remove or guard early exit/exec and stdout redirection in the relevant rcfile (~/.zshrc, $ZDOTDIR/.zshrc, ~/.bash_profile)
  3. Guard rcfile aliases: skip snapshot-hostile config when not interactive ([[ $- != *i* ]] && return)
  4. If unfixable, disable the shell snapshot feature — the failure degrades gracefully (snapshot skipped, session continues)

Example fix

# ~/.zshrc — before
exec tmux                 # shell replaced: marker never printed

# after
if [[ -z "$CODEX_SNAPSHOT" && $- != *i* ]]; then return; fi
# ... interactive-only config below ...
Defensive patterns

Strategy: fallback

Validate before calling

// Cheap preflight: confirm a login shell emits the marker within budget before relying on snapshots
// (reuses the same -lc invocation used by the snapshot path)

Type guard

fn snapshot_has_marker(raw: &str) -> bool {
    raw.contains("# Snapshot file")
}

Try / catch

match write_shell_snapshot(shell_type, &tmp, &cwd).await {
    Ok(()) => finalize(tmp),
    Err(e) if e.to_string().contains("missing marker") => {
        tracing::warn!("snapshot unusable ({e}); continuing without");
        Ok(None) // degrade like try_create does
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Running the snapshot as a login shell (-lc) where an rcfile executes exit/exec, replaces the shell, redirects stdout, or defines a print/echo alias/function that suppresses the marker; a shell that crashes or is killed mid-rcfile; output encoding damage so find("# Snapshot file") never matches.

Common situations: .zshrc/.bash_profile containing an early exit, exec <other-shell>, or stdout redirection; aggressive rcfiles (e.g. deferred-init frameworks) that fork or replace the shell; alias print='print -r -- > /dev/null' style hacks; shells whose rcfiles spawn interactive prompts killed by stdin(Stdio::null()).

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/b5c9d561ffe1d948. Report an issue: GitHub.