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
- Sanitize the session id to the allowed alphabet before calling session_start.
- Generate ids as alphanumeric (or hex/UUID-hyphen form), which passes the check unchanged.
- Truncate or hash over-long identifiers to <=128 bytes (e.g. SHA-256 hex).
- 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
- Generate session ids from a safe alphabet (hex UUIDs qualify).
- Never pass paths, URLs, or display strings as session ids.
- Sanitize (replace disallowed chars) at the id's point of creation.
- Hash or truncate identifiers longer than 128 bytes.
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
- workspace identity must be a lowercase SHA-256 hash
- cloud job id must look like cloud_
- correction must match exactly one active note on the…
- DeepSeek Harness credentials line
- Invalid durable task id
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)