Skip to content

feat(config): graduated deprecation policy for removed config fields#25356

Open
joshcoughlan wants to merge 1 commit intovectordotdev:masterfrom
Automattic:chore/api-deprecate-playground-graphql
Open

feat(config): graduated deprecation policy for removed config fields#25356
joshcoughlan wants to merge 1 commit intovectordotdev:masterfrom
Automattic:chore/api-deprecate-playground-graphql

Conversation

@joshcoughlan
Copy link
Copy Markdown
Contributor

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:

  • 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
    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

Summary

Vector configuration

How did you test this PR?

Change Type

  • Bug fix
  • New feature
  • Dependencies
  • Non-functional (chore, refactoring, docs)
  • Performance

Is this a breaking change?

  • Yes
  • No

Does this PR include user facing changes?

  • Yes. Please add a changelog fragment based on our guidelines.
  • No. A maintainer will apply the no-changelog label to this PR.

References

Notes

  • Please read our Vector contributor resources.
  • Do not hesitate to use @vectordotdev/vector to reach out to us regarding this PR.
  • Some CI checks run only after we manually approve them.
    • We recommend adding a pre-push hook, please see this template.
    • Alternatively, we recommend running the following locally before pushing to the remote branch:
      • make fmt
      • make check-clippy (if there are failures it's possible some of them can be fixed with make clippy-fix)
      • make test
  • After a review is requested, please avoid force pushes to help us review incrementally.
    • Feel free to push as many commits as you want. They will be squashed into one before merging.
    • For example, you can run git merge origin master and git push.
  • If this PR introduces changes Vector dependencies (modifies Cargo.lock), please
    run make build-licenses to regenerate the license inventory and commit the changes (if any). More details on the dd-rust-license-tool.

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>
@joshcoughlan joshcoughlan requested a review from a team as a code owner May 4, 2026 16:32
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/app.rs
Comment on lines +104 to +110
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);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant