Hmbown/CodeWhale · error

invalid session id

Error message

invalid session id

What it means

write_session_archive refuses to build a session archive when the session's metadata.id is not a valid session id (checked by is_valid_session_id). Session ids become tar member names / file paths, so an invalid id could escape the archive layout or produce a corrupt archive.

Solutions

  1. Check the session metadata id; regenerate or repair the session record with a valid id.
  2. Export a different session and re-derive the broken one from its transcript.
  3. If constructing sessions in code, generate ids with the session store's id generator instead of raw strings.

Example fix

// before
let session = SavedSession { metadata: SessionMetadata { id: "../evil".into(), .. } };
// after
let session = SavedSession { metadata: SessionMetadata { id: SessionId::generate(), .. } };
Defensive patterns

Strategy: validation

Validate before calling

fn id_ok(id: &str) -> bool { !id.is_empty() && id.chars().all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_') }
assert!(id_ok(&session.metadata.id), "invalid session id: {:?}", session.metadata.id);

Type guard

fn valid_session(s: &SavedSession) -> bool { is_valid_session_id(&s.metadata.id) }

Try / catch

match write_session_archive(&s, dir, out, opts) { Err(e) if e.kind() == io::ErrorKind::InvalidInput && e.to_string() == "invalid session id" => skip_and_log(&s.metadata.id), r => r?, }

Prevention

When it happens

Trigger: Calling write_session_archive (crates/tui/src/session_export.rs:147) with a SavedSession whose metadata.id contains path separators, is empty, or otherwise fails is_valid_session_id — typically a hand-constructed session record or one imported from an incompatible format.

Common situations: Exporting sessions from an older/newer store with a different id format; constructing SavedSession in tests or scripts with an arbitrary id string; corrupted session metadata file.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/ade927cf8a1048f1. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/session_export.rs:147

///
/// `session` is typically loaded with
/// [`SessionManager::load_session_snapshot`](crate::session_manager::SessionManager::load_session_snapshot)
/// so the archive reflects the durable record without applying resume-time
/// repair. `sessions_dir` is the trusted session store root; pass `None` (or clear
/// [`SessionArchiveOptions::include_artifacts`]) to export the transcript
/// only.
///
/// The archive is streamed to a sibling temporary file and renamed into
/// place, so a failed export never leaves a truncated archive at `output`.
/// An existing `output` is replaced only when `options.overwrite` is set.
pub fn write_session_archive(
    session: &SavedSession,
    sessions_dir: Option<&Path>,
    output: &Path,
    options: SessionArchiveOptions,
) -> io::Result<SessionArchiveSummary> {
    if !is_valid_session_id(&session.metadata.id) {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "invalid session id",
        ));
    }
    if options.compression_level > 9 {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!(
                "xz compression level {} is out of range 0-9",
                options.compression_level
            ),
        ));
    }
    let session_json = session_json(session)?;
    let container_json = container_json(session)?;
    let parent = output
        .parent()
        .filter(|parent| !parent.as_os_str().is_empty())

View on GitHub (pinned to 73e0f67d83)