{"record":{"id":"4a0940a5e2652f45","repo":"Hmbown/CodeWhale","slug":"memory-note-is-empty","errorCode":null,"errorMessage":"memory note is empty","messagePattern":"memory note is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/native_memory.rs","lineNumber":888,"sourceCode":"}\n\n/// Evidence is required on every in-place edit and held to the same bounds\n/// as a note. An unexplained rewrite of durable context is the thing the\n/// journal exists to prevent.\nfn normalize_evidence(evidence: &str) -> Result<String> {\n    normalize_note(evidence).map_err(|_| anyhow!(\"memory edits require non-empty evidence\"))\n}\n\nfn normalize_note(note: &str) -> Result<String> {\n    let note = note.replace(\"\\r\\n\", \"\\n\").replace('\\r', \"\\n\");\n    let note = note\n        .lines()\n        .map(str::trim)\n        .filter(|line| !line.is_empty())\n        .collect::<Vec<_>>()\n        .join(\" \");\n    if note.is_empty() {\n        bail!(\"memory note is empty\");\n    }\n    if note.len() > MAX_NOTE_BYTES {\n        bail!(\"memory note exceeds {MAX_NOTE_BYTES} bytes\");\n    }\n    Ok(note.trim_start_matches('-').trim().to_string())\n}\n\nfn validate_query(query: &str) -> Result<&str> {\n    let query = query.trim();\n    if query.is_empty() || query.chars().count() > MAX_QUERY_CHARS {\n        bail!(\"memory search query is empty or too long\");\n    }\n    Ok(query)\n}\n\nfn safe_component(value: &str) -> Result<String> {\n    if value.is_empty()\n        || value == \".\"","sourceCodeStart":870,"sourceCodeEnd":906,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/native_memory.rs#L870-L906","documentation":"`normalize_note` collapses a note's whitespace into a single line and rejects it if nothing remains. This validation runs before any memory write (remember/revise/retire evidence paths) so empty or whitespace-only notes never enter the store.","triggerScenarios":"Calling `remember`, `revise`, or `retire` with an empty string, a whitespace-only string, or a string whose only content is stripped during normalization (e.g. just \"-\").","commonSituations":"An agent forwards an empty tool argument; upstream code passes an unset variable; a template produced only a bullet marker; a failed extraction yields blank text.","solutions":["Check the note content before calling and skip the call if trimmed text is empty.","Fix the upstream producer that yielded blank text (unset variable, failed extraction).","If trimming a prefix like '-' empties the note, supply real content rather than the marker."],"exampleFix":"// before\nlet note = std::env::var(\"NOTE\").unwrap_or_default();\nstore.remember(&note).await?;\n// after\nlet note = std::env::var(\"NOTE\")?;\nif !note.trim().is_empty() {\n    store.remember(&note).await?;\n}","handlingStrategy":"validation","validationCode":"// Gate the call on non-empty content\nif note.trim().trim_start_matches('-').trim().is_empty() {\n    return Ok(()); // skip: nothing to store\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check trimmed, non-empty text before any remember/revise/retire call.","Fix upstream producers that emit blank strings.","Never rely on '-' or whitespace as note content."],"tags":["memory","validation","empty-input"],"backgroundTag":"empty-required-field","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}