vectordotdev/vector · error
version ' ' has prerelease or build metadata; only plain…
Error message
version '{s}' has prerelease or build metadata; only plain X.Y.Z is allowed What it means
parse_strict_release parses a version string with semver::Version::parse but additionally rejects versions carrying prerelease (e.g. -alpha.1) or build metadata (e.g. +build.5). This mirrors the repository's release-tag convention of plain `vX.Y.Z` tags, so any non-plain version is treated as invalid input for release-based validation and sorting.
Solutions
- Change the version string to a plain three-component release, e.g. "0.45.0-rc.1" → "0.45.0"
- Drop build metadata (everything from `+` onward) and any `-prerelease` suffix
- If a prerelease genuinely must be referenced, use the eventual final release version it shipped in
Example fix
// before
let v = parse_strict_release("0.45.0-rc.1")?;
// after
let v = parse_strict_release("0.45.0")?; Defensive patterns
Strategy: validation
Validate before calling
fn is_plain_release(s: &str) -> bool {
semver::Version::parse(s).map(|v| v.pre.is_empty() && v.build.is_empty()).unwrap_or(false)
}
assert!(is_plain_release("0.45.0")); Prevention
- Copy versions from actual `vX.Y.Z` release tags, not Cargo prerelease output
- Strip `-suffix` and `+metadata` before storing a version in deprecation metadata
- Lint deprecation files for prerelease/build-metadata patterns in CI
When it happens
Trigger: Calling parse_strict_release (directly or via sort_enacted/validate_enacted) with strings like "0.45.0-rc.1", "1.2.3+build", or any X.Y.Z-suffix form instead of a bare "X.Y.Z".
Common situations: A deprecation entry referencing a release candidate or nightly build as its removed_in/deprecated_since version; copy-pasting a version from Cargo/semver output that included build metadata; typo-ed version strings pulled from non-release tags.
Related errors
- component name must be non-empty
- Deprecation fragment
- Duplicate deprecation fragments for `what
- Duplicate enacted entry for
- Enacted entry ' ' has removed_in ( ) that is not in a later…
AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16).
Data as JSON: /api/errors/0dcc0fc914a3d0f0.
Report an issue: GitHub.
Appendix: source
Thrown at vdev/src/utils/deprecation.rs:409
);
}
}
Ok(enacted.len())
}
/// True when `a` is in a later major.minor release than `b`. Equal or smaller
/// major.minor (regardless of patch) returns false.
pub fn later_minor(a: &Version, b: &Version) -> bool {
(a.major, a.minor) > (b.major, b.minor)
}
/// Parse a release version string strictly: only plain `X.Y.Z` is allowed
/// (no prerelease or build metadata). Mirrors the rule that release tags
/// follow `vX.Y.Z`.
pub fn parse_strict_release(s: &str) -> Result<Version> {
let v = Version::parse(s)?;
if !v.pre.is_empty() || !v.build.is_empty() {
bail!("version '{s}' has prerelease or build metadata; only plain X.Y.Z is allowed");
}
Ok(v)
}
/// Render the JSON that `sync_deprecations_cue` would write, without
/// touching disk. Returns the serialized string (with trailing newline) so
/// callers can compare against the on-disk file.
pub fn rendered_json(repo_root: &Path) -> Result<String> {
let dir = repo_root.join(DEPRECATION_DIR);
let pending = read_deprecation_fragments(&dir)?;
let mut data = read_json(repo_root)?;
sort_enacted(&mut data.deprecations_enacted);
data.deprecations_pending = pending_excluding_enacted(&pending, &data.deprecations_enacted);
Ok(serde_json::to_string_pretty(&data)? + "\n")
}
/// Regenerate `DEPRECATIONS_JSON` from `deprecation.d/` (pending) plus the
/// existing enacted entries already in the file.View on GitHub (pinned to bdb87aeaa4)