Hmbown/CodeWhale · error

invalid session id for memory reconcile

Error message

invalid session id for memory reconcile

What it means

native_memory session_start() validates the session id before binding memory state to it: it must be non-empty, at most 128 bytes, and contain only ASCII alphanumerics plus _ - . :. Anything else is refused so the id is safe as a storage key and event id component.

Solutions

  1. Sanitize the session id to the allowed alphabet before calling session_start.
  2. Generate ids as alphanumeric (or hex/UUID-hyphen form), which passes the check unchanged.
  3. Truncate or hash over-long identifiers to <=128 bytes (e.g. SHA-256 hex).
  4. Ensure the id variable is actually populated before the call.

Example fix

// before
session.session_start(workspace, &raw_label)?; // may contain spaces/slashes

// after
let id: String = raw_label.chars().map(|c| if c.is_ascii_alphanumeric() || b"_-.:".contains(&c as u8) { c } else { '_' }).collect();
session.session_start(workspace, &id)?;
Defensive patterns

Strategy: validation

Validate before calling

fn valid_session_id(id: &str) -> bool {
    !id.is_empty()
        && id.len() <= 128
        && id.bytes().all(|b| b.is_ascii_alphanumeric() || b"_-.:".contains(&b))
}

Type guard

fn is_valid_session_id(id: &str) -> bool {
    !id.is_empty() && id.len() <= 128
        && id.bytes().all(|b| b.is_ascii_alphanumeric() || b"_-.:".contains(&b))
}

Prevention

When it happens

Trigger: Calling session_start with an empty string, an id longer than 128 chars, or one containing characters outside [A-Za-z0-9_-.:] — e.g. ids with spaces, slashes, unicode, or a full UUID with braces.

Common situations: Passing a raw path or URL as the session id; embedding a display name with spaces; using a generated id with different alphabet (base64 '+' or '/'); forgetting to initialize the id so it's empty.

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/1ba0de408c7a48a9. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/native_memory.rs:376

                Some(prepared.packet.text)
            }),
            Err(_) => self.prompt_block(workspace, max_entries, max_chars),
        }
    }
    /// Run the session-start boundary for `session_id`. The hook plan maps it
    /// to ReconcilePendingOperations, realized here as detection — contexts
    /// this session prepared but never saw dispatch-acknowledged — because the
    /// store owns the receipts and only a host can replay them. Completion is
    /// recorded durably, so a restarted session reconciles once.
    /// Returns the number of interrupted contexts found.
    pub fn session_start(&self, workspace: &Path, session_id: &str) -> Result<usize> {
        if session_id.is_empty()
            || session_id.len() > 128
            || !session_id
                .bytes()
                .all(|b| b.is_ascii_alphanumeric() || b"_-.:".contains(&b))
        {
            bail!("invalid session id for memory reconcile");
        }
        let (store, access, context_scope) = self.session_binding(workspace, session_id)?;
        let snapshot = workspace::snapshot(workspace, store.dependency_paths(&access)?)?;
        let event = HookEvent {
            id: format!("session-start:{session_id}"),
            boundary: Boundary::SessionStart,
            trace_id: session_id.to_owned(),
            sequence: 0,
            observed_at: store.timestamp(),
            explicit_user_request: false,
            success: None,
        };
        let plan = hooks::plan(
            &HookPolicy {
                enabled: true,
                auto_candidates: false,
                recall_on_task: true,
            },

View on GitHub (pinned to 73e0f67d83)