{"record":{"id":"7911ca9428259cde","repo":"flarum/framework","slug":"step-failed","errorCode":null,"errorMessage":"Step failed","messagePattern":"Step failed","errorType":"exception","errorClass":"StepFailed","httpStatus":null,"severity":"error","filePath":"framework/core/src/Install/Pipeline.php","lineNumber":76,"sourceCode":"    /**\n     * @param callable(): Step $factory\n     * @throws StepFailed\n     */\n    private function runStep(callable $factory): void\n    {\n        $step = $factory();\n\n        $this->fireCallbacks('start', $step);\n\n        try {\n            $step->run();\n            $this->successfulSteps->push($step);\n\n            $this->fireCallbacks('end', $step);\n        } catch (Exception $e) {\n            $this->fireCallbacks('fail', $step);\n\n            throw new StepFailed('Step failed', 0, $e);\n        }\n    }\n\n    private function revertReversibleSteps(): void\n    {\n        foreach ($this->successfulSteps as $step) {\n            if ($step instanceof ReversibleStep) {\n                $this->fireCallbacks('rollback', $step);\n\n                $step->revert();\n            }\n        }\n    }\n\n    private function fireCallbacks(string $event, Step $step): void\n    {\n        if (isset($this->callbacks[$event])) {\n            ($this->callbacks[$event])($step);","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/flarum/framework/blob/4b939f685389bfe8a380e9e28ddf305a1c66950c/framework/core/src/Install/Pipeline.php#L58-L94","documentation":"Generic wrapper exception (StepFailed) thrown by the install Pipeline when any pipeline step throws. The original error is preserved as the previous exception, while 'Step failed' identifies which phase of installation aborted; reversible steps already run are rolled back.","triggerScenarios":"Any Install step (writing config, connecting to DB, running migrations, creating admin user, publishing assets) throwing an Exception during Pipeline::run.","commonSituations":"DB connection failure mid-install; unwritable config directory; migration SQL errors; file permission issues during asset publishing. The real cause is in the wrapped exception.","solutions":["Inspect the previous exception: catch StepFailed and log/getPrevious()->getMessage() for the root cause.","Fix the underlying error reported by the wrapped exception (permissions, DB, disk).","Re-run the installer after fixing; already-completed reversible steps are rolled back so it is safe.","Enable verbose logging via pipeline 'fail' callbacks to capture the failing step name."],"exampleFix":"// before\ntry {\n    $pipeline->run();\n} catch (Exception $e) {\n    echo $e->getMessage(); // 'Step failed' — useless\n}\n// after\ntry {\n    $pipeline->run();\n} catch (StepFailed $e) {\n    $step = ...; // track via 'fail' callback\n    $cause = $e->getPrevious();\n    echo \"Install step {$step} failed: \".$cause?->getMessage();\n}","handlingStrategy":"try-catch","validationCode":"// Pre-flight checks before running the pipeline:\nis_writable($configDir) || throw new RuntimeException(\"{$configDir} is not writable\");\n(new PDO(\"mysql:host={$host};dbname={$db}\", $user, $pass)); // verify DB reachable","typeGuard":"null","tryCatchPattern":"try {\n    $pipeline->run();\n} catch (StepFailed $e) {\n    $logger->error('Install failed', [\n        'step' => $e->getPrevious()?->getMessage(),\n        'previous' => $e->getPrevious(),\n    ]);\n}","preventionTips":["Register a 'fail' callback on the pipeline to log the failing step.","Pre-check DB connectivity and directory permissions before running the installer.","Always unwrap getPrevious() — 'Step failed' is never the root cause."],"tags":["installer","pipeline","wrapper-exception"],"backgroundTag":"invalid-state-transition","analyzedSha":"4b939f685389bfe8a380e9e28ddf305a1c66950c","analyzedAt":"2026-09-15T18:09:20.879Z","contentChangedAt":"2026-09-15T18:09:20.879Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}