{"record":{"id":"16f5558f72d15d52","repo":"phar-io/version","slug":"no-build-metadata-set","errorCode":null,"errorMessage":"No build metadata set","messagePattern":"No build metadata set","errorType":"exception","errorClass":"NoBuildMetaDataException","httpStatus":null,"severity":"error","filePath":"src/Version.php","lineNumber":152,"sourceCode":"\n    public function getPatch(): VersionNumber {\n        return $this->patch;\n    }\n\n    /**\n     * @psalm-assert-if-true BuildMetaData $this->buildMetadata\n     * @psalm-assert-if-true BuildMetaData $this->getBuildMetaData()\n     */\n    public function hasBuildMetaData(): bool {\n        return $this->buildMetadata !== null;\n    }\n\n    /**\n     * @throws NoBuildMetaDataException\n     */\n    public function getBuildMetaData(): BuildMetaData {\n        if (!$this->hasBuildMetaData()) {\n            throw new NoBuildMetaDataException('No build metadata set');\n        }\n\n        return $this->buildMetadata;\n    }\n\n    /**\n     * @param string[] $matches\n     *\n     * @throws InvalidPreReleaseSuffixException\n     */\n    private function parseVersion(array $matches): void {\n        $this->major = new VersionNumber((int)$matches['Major']);\n        $this->minor = isset($matches['Minor']) ? new VersionNumber((int)$matches['Minor']) : new VersionNumber(0);\n        $this->patch = isset($matches['Patch']) ? new VersionNumber((int)$matches['Patch']) : new VersionNumber(0);\n\n        if (isset($matches['PreReleaseSuffix']) && $matches['PreReleaseSuffix'] !== '') {\n            $this->preReleaseSuffix = new PreReleaseSuffix($matches['PreReleaseSuffix']);\n        }","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/phar-io/version/blob/5eeb03f1ee82b3076d72daa5cb85d6b68abad783/src/Version.php#L134-L170","documentation":"NoBuildMetaDataException is thrown by Version::getBuildMetaData when the version string had no '+' build-metadata section, so hasBuildMetaData() returns false. The getter cannot return null due to its return type, so it throws instead. Build metadata is optional in SemVer, so this is an expected condition for most versions.","triggerScenarios":"Calling $version->getBuildMetaData() on a Version like '1.2.3' or '1.2.3-rc.1' (no '+metadata'); equals() internally guards with hasBuildMetaData, but direct calls do not.","commonSituations":"Serializing a version back to string and assuming build metadata always exists; comparing or logging build identifiers of packages installed from stable tags; test code parsing '1.0.0' and then querying metadata.","solutions":["Check $version->hasBuildMetaData() before calling getBuildMetaData().","Catch NoBuildMetaDataException and substitute null or an empty value.","If metadata is required, ensure the input version string includes a '+build' segment before constructing the Version."],"exampleFix":"// before\n$meta = $version->getBuildMetaData();\n\n// after\n$meta = $version->hasBuildMetaData() ? $version->getBuildMetaData() : null;","handlingStrategy":"type-guard","validationCode":"// PHP\nif (strpos($versionString, '+') === false) {\n    // no build metadata; skip metadata handling\n}","typeGuard":"function getMetaOrNull(\\Composer\\Semver\\Version $v): ?\\Composer\\Semver\\BuildMetaData {\n    return $v->hasBuildMetaData() ? $v->getBuildMetaData() : null;\n}","tryCatchPattern":"try {\n    $meta = $version->getBuildMetaData();\n} catch (NoBuildMetaDataException $e) {\n    $meta = null;\n}","preventionTips":["Always call hasBuildMetaData() before getBuildMetaData().","Remember build metadata is optional in SemVer and excluded from precedence comparisons.","When serializing versions, conditionally append '+' . metadata only if present."],"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"}