{"record":{"id":"72e2485d1a2068b3","repo":"phar-io/version","slug":"no-pre-release-suffix-set","errorCode":null,"errorMessage":"No pre-release suffix set","messagePattern":"No pre-release suffix set","errorType":"exception","errorClass":"NoPreReleaseSuffixException","httpStatus":null,"severity":"error","filePath":"src/Version.php","lineNumber":41,"sourceCode":"    private $patch;\n\n    /** @var null|PreReleaseSuffix */\n    private $preReleaseSuffix;\n\n    /** @var null|BuildMetaData */\n    private $buildMetadata;\n\n    public function __construct(string $versionString) {\n        $this->ensureVersionStringIsValid($versionString);\n        $this->originalVersionString = $versionString;\n    }\n\n    /**\n     * @throws NoPreReleaseSuffixException\n     */\n    public function getPreReleaseSuffix(): PreReleaseSuffix {\n        if ($this->preReleaseSuffix === null) {\n            throw new NoPreReleaseSuffixException('No pre-release suffix set');\n        }\n\n        return $this->preReleaseSuffix;\n    }\n\n    public function getOriginalString(): string {\n        return $this->originalVersionString;\n    }\n\n    public function getVersionString(): string {\n        $str = \\sprintf(\n            '%d.%d.%d',\n            $this->getMajor()->getValue() ?? 0,\n            $this->getMinor()->getValue() ?? 0,\n            $this->getPatch()->getValue() ?? 0\n        );\n\n        if (!$this->hasPreReleaseSuffix()) {","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/phar-io/version/blob/5eeb03f1ee82b3076d72daa5cb85d6b68abad783/src/Version.php#L23-L59","documentation":"NoPreReleaseSuffixException is thrown by Version::getPreReleaseSuffix when the version was parsed from a string without a pre-release part (e.g. '1.2.3'), so $this->preReleaseSuffix is null. The getter has a non-nullable return type, so instead of returning null it throws. Callers must check hasPreReleaseSuffix() first.","triggerScenarios":"Calling $version->getPreReleaseSuffix() on a Version constructed from '1.2.3' or '1.2.3+build'; comparing versions with isGreaterThan is safe internally, but direct getter calls on stable versions throw.","commonSituations":"Formatting a version string for output by unconditionally calling getPreReleaseSuffix; logging code that assumes every version has a pre-release; tests that parse a plain stable version and then query the suffix.","solutions":["Call $version->hasPreReleaseSuffix() before getPreReleaseSuffix().","Wrap the call in try/catch for NoPreReleaseSuffixException and treat absence as 'stable'.","If the suffix is genuinely required, validate the input version string contains a '-' pre-release section before constructing."],"exampleFix":"// before\n$suffix = $version->getPreReleaseSuffix();\n\n// after\n$suffix = $version->hasPreReleaseSuffix() ? $version->getPreReleaseSuffix() : null;","handlingStrategy":"type-guard","validationCode":"// PHP\nif (strpos($versionString, '-') === false) {\n    // no pre-release section; skip suffix handling\n}","typeGuard":"function getSuffixOrNull(\\Composer\\Semver\\Version $v): ?\\Composer\\Semver\\PreReleaseSuffix {\n    return $v->hasPreReleaseSuffix() ? $v->getPreReleaseSuffix() : null;\n}","tryCatchPattern":"try {\n    $suffix = $version->getPreReleaseSuffix();\n} catch (NoPreReleaseSuffixException $e) {\n    $suffix = null; // stable release\n}","preventionTips":["Always call hasPreReleaseSuffix() before getPreReleaseSuffix().","Treat missing suffix as a stable release in formatting/logging code.","Never assume a Version parsed from arbitrary input has a pre-release part."],"tags":["semver","null-access","version-parsing","php"],"backgroundTag":"null-argument","analyzedSha":"5eeb03f1ee82b3076d72daa5cb85d6b68abad783","analyzedAt":"2026-09-14T11:12:29.257Z","contentChangedAt":"2026-09-14T11:12:29.257Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}