Skip to content

InvalidObservationException: Invalid start: Observation 'http.client.requests' has already been started #34671

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
viktorgunnarson opened this issue Mar 28, 2025 · 2 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) theme: observability An issue related to observability and tracing type: bug A general bug
Milestone

Comments

@viktorgunnarson
Copy link

Running the test class below with spring-boot 3.3.10 all cases pass, but with spring-boot 3.4.4 the test retryWithObservationRegistryFails() fails with the following error:

Expecting actual throwable to be an instance of:
  org.springframework.web.reactive.function.client.WebClientResponseException
but was:
  io.micrometer.observation.tck.InvalidObservationException: Invalid start: Observation 'http.client.requests' has already been started
START: org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$12(DefaultWebClient.java:458)
STOP: org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$10(DefaultWebClient.java:484)
START: org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$12(DefaultWebClient.java:458)
START: org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$12(DefaultWebClient.java:458)
START: org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$12(DefaultWebClient.java:458)
	at io.micrometer.observation.tck.ObservationValidator.throwInvalidObservationException(ObservationValidator.java:149)
	at io.micrometer.observation.tck.ObservationValidator.onStart(ObservationValidator.java:64)
	at io.micrometer.observation.SimpleObservation.notifyOnObservationStarted(SimpleObservation.java:214)
	...(107 remaining lines not displayed - this can be changed with Assertions.setMaxStackTraceElementsDisplayed)

	at com.example.demo.DemoApplicationTests.retryWithObservationRegistryFails(DemoApplicationTests.java:44)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)

Reproduction example

package com.example.demo;

import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

import org.junit.jupiter.api.Test;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;

import io.micrometer.observation.tck.TestObservationRegistry;

class DemoApplicationTests {

    private final WebClient.Builder webclientBuilder = WebClient.builder()
        .baseUrl("https://httpstat.us/500");

    private final WebClient webClientNoObservationRegistry = webclientBuilder
        .build();

    private final WebClient webClient = webclientBuilder
        .observationRegistry(TestObservationRegistry.create())
        .build();

    @Test
    void noRetryWorks() {
        assertThatExceptionOfType(WebClientResponseException.class).isThrownBy(() ->
            webClient.get().retrieve()
                .bodyToMono(String.class)
                .block()
        );
    }

    @Test
    void retryWithoutObservationRegistryWorks() {
        assertThatExceptionOfType(WebClientResponseException.class).isThrownBy(() ->
            webClientNoObservationRegistry.get().retrieve()
                .bodyToMono(String.class)
                .retry(3)
                .block()
        );
    }

    @Test
    void retryWithObservationRegistryFails() {
        assertThatExceptionOfType(WebClientResponseException.class).isThrownBy(() ->
            webClient.get().retrieve()
                .bodyToMono(String.class)
                .retry(3)
                .block()
        );
    }

}
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Mar 28, 2025
@viktorgunnarson
Copy link
Author

It's the combination of TestObservationRegistry and .retry() that is incompatible since the introduction of ObservationValidator in micrometer 1.14.0 see specifically micrometer-metrics/micrometer#5239

@bclozel bclozel self-assigned this Mar 28, 2025
@bclozel bclozel added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Apr 2, 2025
@bclozel bclozel added this to the 6.2.6 milestone Apr 2, 2025
@bclozel bclozel added theme: observability An issue related to observability and tracing in: web Issues in web modules (web, webmvc, webflux, websocket) labels Apr 2, 2025
@bclozel bclozel closed this as completed in b8158df Apr 2, 2025
@bclozel
Copy link
Member

bclozel commented Apr 2, 2025

Thanks @viktorgunnarson , this is now fixed and will be released with the next 6.2.x maintenance release in 2 weeks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) theme: observability An issue related to observability and tracing type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants