googleapis/mcp-toolbox · error

failed to create introspection request: %w

Error message

failed to create introspection request: %w

What it means

After building the GET request URL, the library creates the outgoing HTTP request with http.NewRequestWithContext. If request construction fails (invalid method/URL combination or a malformed url.URL string), the error is wrapped with this message. This is the GET branch of opaque-token introspection.

Source

Thrown at internal/auth/generic/generic.go:373

	}

	paramName := a.IntrospectionParamName
	if paramName == "" {
		paramName = "token"
	}

	var req *http.Request
	if a.IntrospectionMethod == "GET" {
		u, err := url.Parse(introspectionURL)
		if err != nil {
			return nil, fmt.Errorf("failed to parse introspection URL: %w", err)
		}
		q := u.Query()
		q.Set(paramName, tokenStr)
		u.RawQuery = q.Encode()
		req, err = http.NewRequestWithContext(ctx, "GET", u.String(), nil)
		if err != nil {
			return nil, fmt.Errorf("failed to create introspection request: %w", err)
		}
	} else {
		data := url.Values{}
		data.Set(paramName, tokenStr)
		req, err = http.NewRequestWithContext(ctx, "POST", introspectionURL, strings.NewReader(data.Encode()))
		if err != nil {
			return nil, fmt.Errorf("failed to create introspection request: %w", err)
		}
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}
	req.Header.Set("Accept", "application/json")

	// Send request to auth server's introspection endpoint
	resp, err := a.client.Do(req)
	if err != nil {
		logger.ErrorContext(ctx, "failed to call introspection endpoint: %v", err)
		return nil, &MCPAuthError{Code: http.StatusInternalServerError, Message: fmt.Sprintf("failed to call introspection endpoint: %v", err), ScopesRequired: a.ScopesRequired}
	}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Verify the final introspection URL is valid by decoding it manually or with a curl GET request.
  2. Check that IntrospectionMethod is exactly "GET" (case-sensitive) so the intended branch runs.
  3. Ensure the context passed to the auth service is not pre-cancelled.

Example fix

// before
introspectionMethod: "get"  # falls into POST branch or mishandled
// after
introspectionMethod: "GET"
Defensive patterns

Strategy: validation

Validate before calling

if cfg.IntrospectionMethod != "" && cfg.IntrospectionMethod != "GET" && cfg.IntrospectionMethod != "POST" {
    return fmt.Errorf("introspectionMethod must be GET or POST, got %q", cfg.IntrospectionMethod)
}

Type guard

func isSupportedIntrospectionMethod(m string) bool {
    return m == "" || m == "GET" || m == "POST"
}

Try / catch

claims, err := svc.ValidateMCPAuth(ctx, header)
if err != nil {
    if strings.Contains(err.Error(), "failed to create introspection request") {
        // verify ctx not cancelled and URL valid, then retry once
        if ctx.Err() == nil { claims, err = svc.ValidateMCPAuth(ctx, header) }
    }
    return claims, err
}

Prevention

When it happens

Trigger: IntrospectionMethod is "GET", the parsed URL stringified via u.String() is somehow invalid, or ctx is already cancelled making NewRequestWithContext fail at this layer; err from http.NewRequestWithContext is wrapped here.

Common situations: Extremely rare in practice; usually caused by a corrupted URL after query encoding or an invalid method constant due to custom configuration subclassing.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/1b5f272fab4d6ecf. Report an issue: GitHub.