Skip to content

Include config document path in declarative config error messages - #8953

Open
AstonKrss wants to merge 1 commit into
open-telemetry:mainfrom
AstonKrss:issue-7949-declarative-config-error-paths
Open

AstonKrss wants to merge 1 commit into
open-telemetry:mainfrom
AstonKrss:issue-7949-declarative-config-error-paths

Conversation

@AstonKrss

Copy link
Copy Markdown

Resolves #7949

Motivation

Errors raised while interpreting declarative configuration were generic and
ambiguous, and did not tell you where in the document the problem was:

batch span processor exporter is required but is null

A document can contain several processors, so this is hard to act on. The issue
asks for the message to include the path to the offending node:

.tracer_provider.processors[0].batch exporter is required but is null

Implementation

DeclarativeConfigContext now tracks the path of the configuration node
currently being interpreted:

  • getConfigPath() returns "" at the root, otherwise "." + join(".", segments).
  • withConfigPath(segment, supplier) pushes/pops around a supplier (restores in finally).
  • pushConfigPath(segment) / popConfigPath() for statement-style call sites
    (loops and multi-statement blocks) where a lambda is awkward or where NullAway
    cannot carry the null-check of a nullable getter into the lambda.

FileConfigUtil.requireNonNull(context, object, description) prefixes the message
with getConfigPath(), and a new FileConfigUtil.withConfigPath(context, message)
helper covers messages that are not built via requireNonNull.

Each factory descends into its children by pushing a path segment named after the
corresponding configuration model field, so the segment matches the documented key:

Factory Segments
OpenTelemetryConfigurationFactory propagator, resource, meter_provider, logger_provider, tracer_provider
TracerProviderFactory sampler, processors[i], id_generator, tracer_configurator/development.tracers[i]
LoggerProviderFactory processors[i], logger_configurator/development.loggers[i]
MeterProviderFactory readers[i], views[i], meter_configurator/development.meters[i]
MetricReaderFactory periodic, pull
SpanProcessorFactory batch, simple
LogRecordProcessorFactory batch, simple
SamplerFactory always_record
ComposableSamplerFactory rule_based, parent_threshold
ComposableRuleBasedSamplerFactory rules[i], attribute_values, attribute_patterns
AttributeListFactory attributes[i]

Before / after

- batch span processor exporter is required but is null
+ .tracer_provider.processors[0].batch exporter is required but is null

- always_record sampler .root is required
+ .tracer_provider.sampler.always_record root is required but is null

- parent threshold sampler root is required but is null
+ .tracer_provider.sampler.parent_threshold root is required but is null

Testing

  • New end-to-end test parseAndCreate_ErrorIncludesDocumentPath in
    DeclarativeConfigurationCreateTest reproduces the exact scenario from the issue
    (YAML with tracer_provider.processors[0].batch missing exporter).
  • Updated expectations in SpanProcessorFactoryTest, LogRecordProcessorFactoryTest,
    MetricReaderFactoryTest, and SamplerFactoryTest; the factory calls are now wrapped
    in the corresponding withConfigPath(...) so the assertions verify the real document path.
./gradlew :sdk-extensions:declarative-config:test        # 541 tests, 0 failures
./gradlew :sdk-extensions:declarative-config:spotlessCheck

Notes

  • Change is limited to the declarative-config module and does not alter the public API surface.
  • NullAway (enforced in this repo) requires nullable getters to be hoisted into a local
    variable before use inside a lambda, which is why some call sites use
    push/popConfigPath in try/finally rather than withConfigPath.

…en-telemetry#7949)

Errors thrown while interpreting declarative configuration now include the
path to the offending node in the configuration document, e.g.
".tracer_provider.processors[0].batch exporter is required but is null".

DeclarativeConfigContext tracks the path of the node currently being
interpreted. Factories push/pop path segments as they descend into children,
and FileConfigUtil.requireNonNull / validateSingleKeyValue prefix messages
with the current path.
@AstonKrss
AstonKrss requested a review from a team as a code owner October 16, 2026 08:31
@linux-foundation-easycla

linux-foundation-easycla Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: AstonKrss / name: AstonKrss (d498416)

@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Pull request dashboard status

Waiting on the author · refreshed 2026-11-09 19:26 UTC

Resolve merge conflicts.

Respond to 1 review item (e.g. link a commit, explain why not, ask a follow-up):

  • Top-level threads: 1
Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Should this be with reviewers? Comment /dashboard route:reviewers to route it to them.
  • Anything wrong — including the routing? Report it with what you expected; it helps us improve the dashboard.

@codecov

codecov Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.98492% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.68%. Comparing base (1522a4d) to head (d498416).
⚠️ Report is 41 commits behind head on main.

Files with missing lines Patch % Lines
...nfigure/declarativeconfig/MetricReaderFactory.java 75.00% 2 Missing and 1 partial ⚠️
...ativeconfig/ComposableRuleBasedSamplerFactory.java 94.87% 0 Missing and 2 partials ⚠️
...re/declarativeconfig/ComposableSamplerFactory.java 90.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #8953      +/-   ##
============================================
+ Coverage     90.66%   90.68%   +0.02%     
- Complexity    10888    10914      +26     
============================================
  Files          1015     1015              
  Lines         29736    29806      +70     
  Branches       3877     3882       +5     
============================================
+ Hits          26959    27029      +70     
- Misses         1860     1861       +1     
+ Partials        917      916       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jack-berg jack-berg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hey thanks for taking an interest in this.

I think we need to come at this from a different angle. This approach of iteratively building the path in the factory methods is brittle:

  • It requires the factory methods to be aware of string property value names, which is subject to change and defeats the purpose of the generated type safe accessors.
  • It requires the factory methods to add the path information for all elements, which is error prone.
  • It doesn't consider path for DeclarativeConfigProperties, which is a key interface for reading config info when not bound to particular model type.

I think a better approach would be to look into:

  1. Updating the model generation code to include the ability to capture metadata like this path information.
  2. Similarly, update DeclarativeConfigProperties to capture / expose metadata path information.
  3. Update parsing logic to add path metadata to model types when parsing YAML. Whenever converting to DeclarativeConfigProperties, or back to a type, make sure to carry the correct path metadata.

The tricky part is that the model types also can sometimes carry additional properties which are represented using things like generic List, Map<String, Object>. I.e. types which are neither our generated model types or DeclarativeConfigProperties. How we associate path metadata with these? I think the answer probably lies in making all additional properties work in terms of DeclarativeConfigProperties, getting rid of the generic List, Map<String, Object> representation in favor of List, Map<String, DeclarativeConfigProperties>.

But as you can probably see, this get complicated.

You're welcome to take a crack at it.

@jack-berg jack-berg added the needs author feedback Waiting for additional feedback from the author label Nov 9, 2026

This branch has not been deployed

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

Labels

needs author feedback Waiting for additional feedback from the author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Better declarative config error messages

2 participants