{"record":{"id":"b5c9d561ffe1d948","repo":"openai/codex","slug":"snapshot-output-missing-marker-marker","errorCode":null,"errorMessage":"Snapshot output missing marker {marker}","messagePattern":"Snapshot output missing marker (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"codex-rs/core/src/shell_snapshot.rs","lineNumber":240,"sourceCode":"    let snapshot_path = output_path.display();\n    fs::write(output_path, snapshot)\n        .await\n        .with_context(|| format!(\"Failed to write snapshot to {snapshot_path}\"))?;\n\n    Ok(())\n}\n\nasync fn capture_snapshot(shell: &Shell, cwd: &AbsolutePathBuf) -> Result<String> {\n    let shell_type = shell.shell_type;\n    let script = snapshot_script(shell_type)\n        .ok_or_else(|| anyhow!(\"Shell snapshotting is not yet supported for {shell_type:?}\"))?;\n    run_shell_script(shell, &script, cwd).await\n}\n\nfn strip_snapshot_preamble(snapshot: &str) -> Result<String> {\n    let marker = \"# Snapshot file\";\n    let Some(start) = snapshot.find(marker) else {\n        bail!(\"Snapshot output missing marker {marker}\");\n    };\n\n    Ok(snapshot[start..].to_string())\n}\n\nasync fn validate_snapshot(\n    shell: &Shell,\n    snapshot_path: &AbsolutePathBuf,\n    cwd: &AbsolutePathBuf,\n) -> Result<()> {\n    let snapshot_path_display = snapshot_path.display();\n    let script = format!(\"set -e; . \\\"{snapshot_path_display}\\\"\");\n    run_script_with_timeout(\n        shell,\n        &script,\n        SNAPSHOT_TIMEOUT,\n        /*use_login_shell*/ false,\n        cwd,","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/core/src/shell_snapshot.rs#L222-L258","documentation":"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.","triggerScenarios":"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.","commonSituations":".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()).","solutions":["Reproduce manually: run the printed login-shell command with stdin closed and check stdout for '# Snapshot file' — the offending rcfile line will be obvious","Remove or guard early exit/exec and stdout redirection in the relevant rcfile (~/.zshrc, $ZDOTDIR/.zshrc, ~/.bash_profile)","Guard rcfile aliases: skip snapshot-hostile config when not interactive ([[ $- != *i* ]] && return)","If unfixable, disable the shell snapshot feature — the failure degrades gracefully (snapshot skipped, session continues)"],"exampleFix":"# ~/.zshrc — before\nexec tmux                 # shell replaced: marker never printed\n\n# after\nif [[ -z \"$CODEX_SNAPSHOT\" && $- != *i* ]]; then return; fi\n# ... interactive-only config below ...","handlingStrategy":"fallback","validationCode":"// Cheap preflight: confirm a login shell emits the marker within budget before relying on snapshots\n// (reuses the same -lc invocation used by the snapshot path)","typeGuard":"fn snapshot_has_marker(raw: &str) -> bool {\n    raw.contains(\"# Snapshot file\")\n}","tryCatchPattern":"match write_shell_snapshot(shell_type, &tmp, &cwd).await {\n    Ok(()) => finalize(tmp),\n    Err(e) if e.to_string().contains(\"missing marker\") => {\n        tracing::warn!(\"snapshot unusable ({e}); continuing without\");\n        Ok(None) // degrade like try_create does\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Keep rcfiles free of early exit/exec and stdout redirection","Test shell startup with stdin closed: zsh -lc 'print test' should print output","Don't alias/override print/echo in rcfiles","Treat snapshot failures as telemetry (failure_reason already recorded), not as fatal"],"tags":["rust","codex","shell-snapshot","rcfile","output-parsing"],"backgroundTag":"missing-output-marker","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}