{"record":{"id":"7a28fd068118a98e","repo":"ogham/exa","slug":"details-table-options-not-given","errorCode":null,"errorMessage":"Details table options not given!","messagePattern":"Details table options not given!","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/output/grid_details.rs","lineNumber":146,"sourceCode":"            git_ignoring:  self.git_ignoring,\n            git:           self.git,\n        }\n    }\n\n    // This doesn’t take an IgnoreCache even though the details one does\n    // because grid-details has no tree view.\n\n    pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {\n        if let Some((grid, width)) = self.find_fitting_grid() {\n            write!(w, \"{}\", grid.fit_into_columns(width))\n        }\n        else {\n            self.give_up().render(w)\n        }\n    }\n\n    pub fn find_fitting_grid(&mut self) -> Option<(grid::Grid, grid::Width)> {\n        let options = self.details.table.as_ref().expect(\"Details table options not given!\");\n\n        let drender = self.details_for_column();\n\n        let (first_table, _) = self.make_table(options, &drender);\n\n        let rows = self.files.iter()\n                       .map(|file| first_table.row_for_file(file, file_has_xattrs(file)))\n                       .collect::<Vec<_>>();\n\n        let file_names = self.files.iter()\n                             .map(|file| self.file_style.for_file(file, self.theme).paint().promote())\n                             .collect::<Vec<_>>();\n\n        let mut last_working_grid = self.make_grid(1, options, &file_names, rows.clone(), &drender);\n\n        if file_names.len() == 1 {\n            return Some((last_working_grid, 1));\n        }","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/ogham/exa/blob/3d1edbb47052cb416ef9478106c3907586da5150/src/output/grid_details.rs#L128-L164","documentation":"This is a Rust panic from expect() in the grid-details renderer (src/output/grid_details.rs:146). A GridDetails Render expects its DetailsOptions to carry table formatting options (details.table: Option<TableOptions>); when that field is None, find_fitting_grid() panics with 'Details table options not given!' before any output is written. The invariant exists because the grid-details view (--long --grid) draws details tables into columns, and a table with no column options cannot be built. In the shipped exa binary the mode selector (src/options/view.rs) only sets table to Some when --long is given, so the panic means a Render was constructed or reused with DetailsOptions left at its default table: None.","triggerScenarios":"Programmatically building grid_details::Render and calling render() or find_fitting_grid() with a DetailsOptions created via its default constructor (table: None, see src/options/view.rs:117) instead of one deduced with --long (src/options/view.rs:136, TableOptions::deduce). It also fires if user code swaps/copies the DetailsOptions struct between modes, or a fork drives Mode::GridDetails rendering without matching option deduction.","commonSituations":"Almost exclusively hits developers embedding exa's renderer or forking the CLI who assemble Options by hand; end users of the exa binary should not reach it because --grid --long always deduces table options. Typical story: copy-pasting the Render construction from the codebase but skipping the options::view::Options::deduce step, or unit tests that construct a Render directly.","solutions":["Populate the table options before rendering: construct the whole options set through exa's own deduction (options::view::Options::deduce with --long and --grid semantics) so details.table is Some(TableOptions::deduce(...)).","Or set the field directly: render.details.table = Some(TableOptions { columns, ..}) with the columns you want (name, size, permissions, and so on) before calling render().","If you did not mean to show details, do not use the grid-details renderer; use the plain grid renderer (Mode::Grid) which needs no table options.","Longer term, replace the runtime expect with a type-level guarantee (a newtype that can only be built with table options), or fall back to self.give_up() rendering when table is None instead of panicking."],"exampleFix":"// before\nlet details = DetailsOptions::default();               // table: None  -> panics in render()\nlet render = grid_details::Render { details: &details, /* ... */ };\nrender.render(&mut out)?;\n\n// after: always pair grid-details with a table, like --long --grid does\nlet details = DetailsOptions {\n    table: Some(TableOptions::deduce(&matches, vars)?), // or a hand-built Columns set\n    ..DetailsOptions::default()\n};\nlet render = grid_details::Render { details: &details, /* ... */ };\nrender.render(&mut out)?;","handlingStrategy":"validation","validationCode":"// Before building or rendering a grid_details::Render:\nuse crate::output::details;\n\nfn can_render_grid_details(details: &details::Options) -> bool {\n    // grid_details::Render::find_fitting_grid() panics without table options\n    details.table.is_some()\n}\n\nif !can_render_grid_details(&opts.details) {\n    // choose the plain grid mode, or build the missing TableOptions first\n    eprintln!(\"grid-details requires details table options (--long)\");\n}","typeGuard":"fn as_grid_details_ready(details: &details::Options)\n    -> Option<&details::Options> {\n    // Only hand the Render over when the invariant expected by\n    // grid_details.rs:146 holds.\n    details.table.as_ref().map(|_| details)\n}","tryCatchPattern":"// Panics are not Result-based; if you must call untrusted configuration,\n// isolate the render call behind catch_unwind:\nlet result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    render.render(&mut out)\n}));\nmatch result {\n    Ok(Ok(())) => {}\n    Ok(Err(e)) => { /* io error */ }\n    Err(_panic) => {\n        // 'Details table options not given!' or any other invariant panic:\n        // log and fall back to the plain grid renderer\n    }\n}","preventionTips":["Always derive view options through exa's own options::view::Options::deduce with --long and --grid instead of struct literals; it guarantees table: Some(...).","Treat details.table = None as 'details view not configured'; never feed such Options into grid_details::Render.","If you copy Render construction examples from the codebase, copy the matching Options construction from src/options/view.rs:117-136 as well.","Add a unit test that asserts opts.details.table.is_some() before every code path that renders Mode::GridDetails."],"tags":["rust","panic","configuration","missing-option","renderer"],"backgroundTag":"missing-required-option","analyzedSha":"3d1edbb47052cb416ef9478106c3907586da5150","analyzedAt":"2026-08-16T22:11:59.736Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}