{"record":{"id":"d381d40c831f086e","repo":"symfony/process","slug":"start-time-is-only-available-after-process-start","errorCode":null,"errorMessage":"Start time is only available after process start.","messagePattern":"Start time is only available after process start\\.","errorType":"exception","errorClass":"LogicException","httpStatus":null,"severity":"error","filePath":"Process.php","lineNumber":1238,"sourceCode":"            $this->stop(0);\n\n            throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);\n        }\n\n        if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {\n            $this->stop(0);\n\n            throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);\n        }\n    }\n\n    /**\n     * @throws LogicException in case process is not started\n     */\n    public function getStartTime(): float\n    {\n        if (!$this->isStarted()) {\n            throw new LogicException('Start time is only available after process start.');\n        }\n\n        return $this->starttime;\n    }\n\n    /**\n     * Defines options to pass to the underlying proc_open().\n     *\n     * @see https://php.net/proc_open for the options supported by PHP.\n     *\n     * Enabling the \"create_new_console\" option allows a subprocess to continue\n     * to run after the main process exited, on both Windows and *nix\n     */\n    public function setOptions(array $options): void\n    {\n        if ($this->isRunning()) {\n            throw new RuntimeException('Setting options while the process is running is not possible.');\n        }","sourceCodeStart":1220,"sourceCodeEnd":1256,"githubUrl":"https://github.com/symfony/process/blob/99b85026db14a68f02c6f3eeb01a1170ca25c491/Process.php#L1220-L1256","documentation":"getStartTime() throws this LogicException when the process has never been started. The starttime property is only recorded in start(), so before any start the value is meaningless and the getter refuses to return it.","triggerScenarios":"Calling getStartTime() on a freshly constructed Process that has not been started; also on a Process whose start failed before recording the time.","commonSituations":"Telemetry/logging code measuring elapsed time that reads getStartTime() unconditionally; components receiving a Process object without knowing whether start() was called.","solutions":["Guard with if ($process->isStarted()) before reading getStartTime().","Track start time in caller code (microtime(true)) right before calling start().","Call start() first, or throw/log a domain-level error when the process was expected to be running."],"exampleFix":"// before\n$elapsed = microtime(true) - $process->getStartTime(); // LogicException\n\n// after\nif ($process->isStarted()) {\n    $elapsed = microtime(true) - $process->getStartTime();\n}","handlingStrategy":"validation","validationCode":"$startTime = $process->isStarted() ? $process->getStartTime() : null;","typeGuard":null,"tryCatchPattern":"try {\n    $startTime = $process->getStartTime();\n} catch (\\LogicException $e) {\n    $startTime = null; // never started\n}","preventionTips":["Record your own microtime(true) before calling start() as the source of truth.","Assert isStarted() in telemetry/logging helpers that read process timing."],"tags":["process","symfony","logic-exception","not-started","invalid-state-transition"],"backgroundTag":"invalid-state-transition","analyzedSha":"99b85026db14a68f02c6f3eeb01a1170ca25c491","analyzedAt":"2026-09-14T11:23:33.683Z","contentChangedAt":"2026-09-14T11:23:33.683Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}