{"record":{"id":"03a80596ba47b8af","repo":"gitbutlerapp/gitbutler","slug":"no-rebase-steps-provided","errorCode":null,"errorMessage":"No rebase steps provided","messagePattern":"No rebase steps provided","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-rebase/src/lib.rs","lineNumber":146,"sourceCode":"        self\n    }\n\n    /// Performs a rebase on top of a given base, according to the provided steps, or fails if no step was provided.\n    /// It does not actually create new git references nor does it update existing ones, it only deals with\n    /// altering commits and providing the information needed to update refs.\n    ///\n    /// Use it to\n    ///\n    ///  - drop commits\n    ///  - insert new commits\n    ///  - reorder commits\n    ///  - rewrite the history at will\n    ///\n    /// **However, note that it will also make all input commits sequential, so the caller must assure\n    /// these actually form a 'line'.**\n    pub fn rebase(&mut self) -> Result<RebaseOutput> {\n        if self.steps.is_empty() {\n            return Err(anyhow!(\"No rebase steps provided\"));\n        }\n        let pick_mode = if self.rebase_noops {\n            PickMode::Unconditionally\n        } else {\n            PickMode::SkipIfNoop\n        };\n        rebase(\n            self.repo,\n            self.base,\n            self.base_substitute,\n            std::mem::take(&mut self.steps),\n            pick_mode,\n        )\n    }\n}\n\nimpl Rebase<'_> {\n    /// Pick, Merge and Fixup operations:","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-rebase/src/lib.rs#L128-L164","documentation":"`Rebase::rebase()` executes the step list accumulated via `Rebase::steps()` and refuses to run when that list is empty — a rebase with nothing to pick, merge, fixup, or reference is treated as a programming error rather than a no-op. The builder validates each step as it is added, but the empty-list check happens at execution time.","triggerScenarios":"Constructing `Rebase::new(repo, base, substitute)` and calling `.rebase()` without ever calling `.steps(...)`; or passing an empty iterator to `.steps([])` which adds (and validates) nothing.","commonSituations":"Dynamic step generation that filters out every commit (e.g. empty diff range, no commits between base and target); early-return logic that skips adding steps but still calls rebase; tests that build the builder mechanically.","solutions":["Check your step list is non-empty before calling `rebase()` and skip the operation if there is nothing to do","Debug why step generation produced zero items — usually an over-aggressive filter or an already-up-to-date range","Return early with `Ok(default)` semantics at the call site when 'nothing to rebase' is a valid outcome"],"exampleFix":"// before\nlet out = rebase.rebase()?; // Err: No rebase steps provided\n\n// after\nlet out = if steps.is_empty() {\n    return Ok(RebaseOutput::default()); // or skip the rebase entirely\n} else {\n    rebase.steps(steps)?.rebase()?\n};","handlingStrategy":"validation","validationCode":"if steps.is_empty() {\n    return Ok(RebaseOutput::default()); // nothing to rebase is a valid outcome here\n}\nrebase.steps(steps)?.rebase()?;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Guard step-generation code so it never returns an empty list silently — log when it does","Treat 'no steps' as a skip at the call site rather than an error when that is a valid state","Add a builder lint/test that every code path either adds steps or skips rebase()"],"tags":["rust","rebase","validation","api-misuse","builder"],"backgroundTag":"empty-input-collection","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}