feat(config): graduated deprecation policy for removed config fields#25356
feat(config): graduated deprecation policy for removed config fields#25356joshcoughlan wants to merge 1 commit intovectordotdev:masterfrom
Conversation
Adds a small reusable mechanism for handling configuration fields that have
been removed upstream but may still appear in user configs. Rather than
breaking those configs cold, a removed field stays accepted for a window
of minor releases (12, ~one year at Vector's monthly cadence) with a
warn! at startup that names the exact future Vector version in which the
field will become a hard configuration error. Past that window, loading a
config that still sets the field fails fast with a "remove this field"
message.
Operators get a deterministic deadline; nobody is surprised by a silent
breaking change.
The policy lives in a new module, src/config/deprecation, so future
removals can opt into the same behavior with a single call site.
Per-field metadata is just (path, deprecated_in_minor, note).
First user: api.playground and api.graphql, both removed in 0.55.0 with
the GraphQL-to-gRPC migration. They were previously rejected outright,
which broke any config still carrying them after upgrade. With this
change they parse as Option<bool>, are silently ignored at runtime, and
emit a deprecation warning naming the future version in which they will
be rejected.
Implementation:
* src/config/deprecation.rs: VectorMinor, DeprecationStage,
stage_for(deprecated, current), current_minor() (parses
CARGO_PKG_VERSION), check_deprecated_field(path, deprecated_in,
note). 9 unit tests covering every transition.
* src/config/api.rs: playground/graphql restored as Option<bool>
with #[configurable(deprecated)] and docs::hidden so they don't
appear in the schema. Options::check_deprecated_fields() collects
all errors so users see every issue at once.
* src/app.rs: Application::from_config calls
check_deprecated_fields() and returns exitcode::CONFIG if any
field has reached the error stage.
WARN_WINDOW_MINORS = 12 is a tunable constant. Tests are written
against the constant so changing it does not require updating
hard-coded version assertions.
authors: joshcoughlan
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6f7070a710
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| let api = { | ||
| if let Err(errors) = config.api.check_deprecated_fields() { | ||
| for e in &errors { | ||
| error!(message = %e, internal_log_rate_limit = false); | ||
| } | ||
| return Err(exitcode::CONFIG); | ||
| } |
There was a problem hiding this comment.
Apply deprecated-field checks to all config load paths
This change enforces api.check_deprecated_fields() only in ApplicationConfig::from_config, so the new hard-error stage is bypassed anywhere a Config is loaded without going through that constructor (notably vector validate and runtime reloads via --watch-config/SIGHUP). In those paths, configs that should be rejected after the warn window can still be accepted, which breaks the promised “deterministic deadline” and causes inconsistent behavior between validation/reload and cold start.
Useful? React with 👍 / 👎.
Adds a small reusable mechanism for handling configuration fields that have been removed upstream but may still appear in user configs. Rather than breaking those configs cold, a removed field stays accepted for a window of minor releases (12, ~one year at Vector's monthly cadence) with a warn! at startup that names the exact future Vector version in which the field will become a hard configuration error. Past that window, loading a config that still sets the field fails fast with a "remove this field" message.
Operators get a deterministic deadline; nobody is surprised by a silent breaking change.
The policy lives in a new module, src/config/deprecation, so future removals can opt into the same behavior with a single call site. Per-field metadata is just (path, deprecated_in_minor, note).
First user: api.playground and api.graphql, both removed in 0.55.0 with the GraphQL-to-gRPC migration. They were previously rejected outright, which broke any config still carrying them after upgrade. With this change they parse as Option, are silently ignored at runtime, and emit a deprecation warning naming the future version in which they will be rejected.
Implementation:
with #[configurable(deprecated)] and docs::hidden so they don't appear in the schema. Options::check_deprecated_fields() collects all errors so users see every issue at once.
WARN_WINDOW_MINORS = 12 is a tunable constant. Tests are written against the constant so changing it does not require updating hard-coded version assertions.
authors: joshcoughlan
Summary
Vector configuration
How did you test this PR?
Change Type
Is this a breaking change?
Does this PR include user facing changes?
no-changeloglabel to this PR.References
Notes
@vectordotdev/vectorto reach out to us regarding this PR.pre-pushhook, please see this template.make fmtmake check-clippy(if there are failures it's possible some of them can be fixed withmake clippy-fix)make testgit merge origin masterandgit push.Cargo.lock), pleaserun
make build-licensesto regenerate the license inventory and commit the changes (if any). More details on the dd-rust-license-tool.