{"record":{"id":"732efae5f64d15bf","repo":"aaif-goose/goose","slug":"export-canceled","errorCode":null,"errorMessage":"Export canceled","messagePattern":"Export canceled","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"info","filePath":"crates/goose-cli/src/commands/session.rs","lineNumber":412,"sourceCode":"            let display_text = format!(\"{} - {} ({})\", s.updated_at, truncated_desc, s.id);\n            (display_text, s.clone())\n        })\n        .collect();\n\n    // Add each session as an option\n    for display_text in display_map.keys() {\n        selector = selector.item(display_text.clone(), display_text.clone(), \"\");\n    }\n\n    // Add a cancel option\n    let cancel_value = String::from(\"cancel\");\n    selector = selector.item(cancel_value, \"Cancel\", \"Cancel export\");\n\n    // Get user selection\n    let selected_display_text: String = selector.interact()?;\n\n    if selected_display_text == \"cancel\" {\n        return Err(anyhow::anyhow!(\"Export canceled\"));\n    }\n\n    // Retrieve the selected session\n    if let Some(session) = display_map.get(&selected_display_text) {\n        Ok(session.id.clone())\n    } else {\n        Err(anyhow::anyhow!(\"Invalid selection\"))\n    }\n}\n","sourceCodeStart":394,"sourceCodeEnd":422,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/commands/session.rs#L394-L422","documentation":"The interactive export picker appends a literal 'Cancel' item; when the user selects it, the flow returns this anyhow error (hence a non-zero exit code) even though it is a normal, user-initiated abort. It is control flow expressed as an error, not a malfunction.","triggerScenarios":"Running `goose session export` without an ID, then choosing 'Cancel' in the selector.","commonSituations":"Browsing sessions interactively and backing out; scripts calling export without an ID that receive unexpected stdin content.","solutions":["Re-run and pick a session, or press the selector's quit key instead","Pass the session ID directly to `goose session export <id>` to skip the prompt entirely"],"exampleFix":"# before\ngoose session export        # picker -> Cancel -> Err\n# after\ngoose session export 20260101_000000_full-id -f json","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match prompt_interactive_session_selection(&sm).await {\n    Err(e) if e.to_string() == \"Export canceled\" => {\n        std::process::exit(0); // user-initiated cancel: exit clean, not as failure\n    }\n    other => other,\n}","preventionTips":["Treat 'Export canceled' as exit code 0 in wrappers — it is a normal user abort","Use the non-interactive form with an explicit session ID in CI/scripts"],"tags":["session","interactive","user-cancel","export"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}