You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2025/01/29 08:17:12 UTC

(maven) branch master updated: [MNG-8519] Introduce Request / Results / RequestTrace (#2050)

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new 2155d9f0c2 [MNG-8519] Introduce Request / Results / RequestTrace (#2050)
2155d9f0c2 is described below

commit 2155d9f0c240a0d01b3446868b46357924392738
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Wed Jan 29 09:17:07 2025 +0100

    [MNG-8519] Introduce Request / Results / RequestTrace (#2050)
---
 api/maven-api-core/pom.xml                         |   5 +
 .../main/java/org/apache/maven/api/Session.java    |   3 -
 .../ArtifactCoordinatesFactoryRequest.java         |  28 ++-
 .../api/services/ArtifactDeployerRequest.java      |  27 ++-
 .../maven/api/services/ArtifactFactoryRequest.java |  29 ++-
 .../api/services/ArtifactInstallerRequest.java     |  26 ++-
 .../api/services/ArtifactResolverRequest.java      |  23 ++-
 .../maven/api/services/ArtifactResolverResult.java |   2 +-
 .../org/apache/maven/api/services/BaseRequest.java |  12 +-
 .../DependencyCoordinatesFactoryRequest.java       |  26 ++-
 .../api/services/DependencyResolverRequest.java    |  56 +++++-
 .../api/services/DependencyResolverResult.java     |   2 +-
 .../maven/api/services/ModelBuilderRequest.java    |  33 +++-
 .../maven/api/services/ModelBuilderResult.java     |   2 +-
 .../maven/api/services/ProjectBuilderRequest.java  |  27 ++-
 .../maven/api/services/ProjectBuilderResult.java   |   2 +-
 .../org/apache/maven/api/services/Request.java     |  91 ++++++++++
 .../apache/maven/api/services/RequestTrace.java    |  62 +++++++
 .../{SettingsBuilderResult.java => Result.java}    |  34 ++--
 .../maven/api/services/SettingsBuilderRequest.java |  24 ++-
 .../maven/api/services/SettingsBuilderResult.java  |   2 +-
 .../api/services/ToolchainsBuilderRequest.java     |  22 ++-
 .../api/services/ToolchainsBuilderResult.java      |   2 +-
 .../api/services/VersionRangeResolverRequest.java  |  23 ++-
 .../api/services/VersionRangeResolverResult.java   |   2 +-
 .../maven/api/services/VersionResolverRequest.java |  23 ++-
 .../maven/api/services/VersionResolverResult.java  |   2 +-
 .../api/services/RequestImplementationTest.java    |  79 +++++++++
 .../maven/api/services/RequestTraceTest.java       |  85 +++++++++
 .../aether/ReverseTreeRepositoryListener.java      |   8 +-
 .../maven/internal/impl/DefaultProjectBuilder.java |  12 +-
 .../DefaultPluginDependenciesResolver.java         |  13 +-
 .../internal/DefaultPluginPrefixResolver.java      |   2 +-
 .../internal/DefaultPluginVersionResolver.java     |   2 +-
 .../org/apache/maven/impl/AbstractSession.java     |  17 ++
 .../apache/maven/impl/DefaultArtifactResolver.java |  18 +-
 .../maven/impl/DefaultDependencyResolver.java      | 194 +++++++++++----------
 .../impl/DefaultDependencyResolverResult.java      |  17 +-
 .../apache/maven/impl/DefaultSettingsBuilder.java  |  13 +-
 .../maven/impl/DefaultToolchainsBuilder.java       |  14 +-
 .../maven/impl/DefaultVersionRangeResolver.java    |  21 ++-
 .../apache/maven/impl/DefaultVersionResolver.java  |  16 +-
 .../org/apache/maven/impl/InternalSession.java     |  24 +++
 .../org/apache/maven/impl/RequestTraceHelper.java  | 138 +++++++++++++++
 .../maven/impl/model/DefaultModelBuilder.java      |  84 ++++++---
 .../impl/model/DefaultModelBuilderResult.java      |  10 +-
 .../resolver/DefaultArtifactDescriptorReader.java  |   2 +
 .../maven/impl/resolver/RequestTraceHelper.java    |  69 --------
 .../apache/maven/impl/RequestTraceHelperTest.java  |  87 +++++++++
 .../impl/model/DefaultModelBuilderResultTest.java  | 109 ++++++++++++
 .../maven/impl/standalone/RequestTraceTest.java    | 106 +++++++++++
 51 files changed, 1414 insertions(+), 316 deletions(-)

diff --git a/api/maven-api-core/pom.xml b/api/maven-api-core/pom.xml
index 6c1bb03326..4d97cb9d7f 100644
--- a/api/maven-api-core/pom.xml
+++ b/api/maven-api-core/pom.xml
@@ -65,6 +65,11 @@
       <artifactId>junit-jupiter-api</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
 </project>
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java
index 39ae21a0cc..d9899dcc4c 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java
@@ -38,9 +38,6 @@
 /**
  * The session to install / deploy / resolve artifacts and dependencies.
  *
- * TODO: add request trace so that requests can be linked together and through the resolver
- * TODO: add a Request interface holding session + parent request
- *
  * @since 4.0.0
  */
 @Experimental
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinatesFactoryRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinatesFactoryRequest.java
index cf96d490fd..074c9bcebd 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinatesFactoryRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinatesFactoryRequest.java
@@ -34,10 +34,7 @@
  */
 @Experimental
 @Immutable
-public interface ArtifactCoordinatesFactoryRequest {
-
-    @Nonnull
-    Session getSession();
+public interface ArtifactCoordinatesFactoryRequest extends Request<Session> {
 
     String getGroupId();
 
@@ -112,6 +109,7 @@ static ArtifactFactoryRequestBuilder builder() {
     @NotThreadSafe
     class ArtifactFactoryRequestBuilder {
         private Session session;
+        private RequestTrace trace;
         private String groupId;
         private String artifactId;
         private String version;
@@ -127,6 +125,11 @@ public ArtifactFactoryRequestBuilder session(Session session) {
             return this;
         }
 
+        public ArtifactFactoryRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         public ArtifactFactoryRequestBuilder groupId(String groupId) {
             this.groupId = groupId;
             return this;
@@ -164,7 +167,7 @@ public ArtifactFactoryRequestBuilder coordinateString(String coordinateString) {
 
         public ArtifactCoordinatesFactoryRequest build() {
             return new DefaultArtifactFactoryRequestArtifact(
-                    session, groupId, artifactId, version, classifier, extension, type, coordinateString);
+                    session, trace, groupId, artifactId, version, classifier, extension, type, coordinateString);
         }
 
         private static class DefaultArtifactFactoryRequestArtifact extends BaseRequest<Session>
@@ -180,6 +183,7 @@ private static class DefaultArtifactFactoryRequestArtifact extends BaseRequest<S
             @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultArtifactFactoryRequestArtifact(
                     @Nonnull Session session,
+                    RequestTrace trace,
                     String groupId,
                     String artifactId,
                     String version,
@@ -187,7 +191,7 @@ private static class DefaultArtifactFactoryRequestArtifact extends BaseRequest<S
                     String extension,
                     String type,
                     String coordinatesString) {
-                super(session);
+                super(session, trace);
                 this.groupId = groupId;
                 this.artifactId = artifactId;
                 this.version = version;
@@ -230,6 +234,18 @@ public String getType() {
             public String getCoordinatesString() {
                 return coordinatesString;
             }
+
+            @Override
+            public String toString() {
+                return "ArtifactFactoryRequestArtifact[" + "groupId='"
+                        + groupId + '\'' + ", artifactId='"
+                        + artifactId + '\'' + ", version='"
+                        + version + '\'' + ", classifier='"
+                        + classifier + '\'' + ", extension='"
+                        + extension + '\'' + ", type='"
+                        + type + '\'' + ", coordinatesString='"
+                        + coordinatesString + '\'' + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java
index 3c5dba3d9f..c2eaedf58b 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java
@@ -27,6 +27,7 @@
 import org.apache.maven.api.annotations.Experimental;
 import org.apache.maven.api.annotations.Immutable;
 import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
 
 import static java.util.Objects.requireNonNull;
 
@@ -37,10 +38,7 @@
  */
 @Experimental
 @Immutable
-public interface ArtifactDeployerRequest {
-
-    @Nonnull
-    Session getSession();
+public interface ArtifactDeployerRequest extends Request<Session> {
 
     @Nonnull
     RemoteRepository getRepository();
@@ -69,6 +67,7 @@ static ArtifactDeployerRequest build(
 
     class ArtifactDeployerRequestBuilder {
         Session session;
+        RequestTrace trace;
         RemoteRepository repository;
         Collection<ProducedArtifact> artifacts;
         int retryFailedDeploymentCount;
@@ -81,6 +80,12 @@ public ArtifactDeployerRequestBuilder session(Session session) {
             return this;
         }
 
+        @Nonnull
+        public ArtifactDeployerRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         @Nonnull
         public ArtifactDeployerRequestBuilder repository(RemoteRepository repository) {
             this.repository = repository;
@@ -99,7 +104,8 @@ public ArtifactDeployerRequestBuilder retryFailedDeploymentCount(int retryFailed
 
         @Nonnull
         public ArtifactDeployerRequest build() {
-            return new DefaultArtifactDeployerRequest(session, repository, artifacts, retryFailedDeploymentCount);
+            return new DefaultArtifactDeployerRequest(
+                    session, trace, repository, artifacts, retryFailedDeploymentCount);
         }
 
         private static class DefaultArtifactDeployerRequest extends BaseRequest<Session>
@@ -111,10 +117,11 @@ private static class DefaultArtifactDeployerRequest extends BaseRequest<Session>
 
             DefaultArtifactDeployerRequest(
                     @Nonnull Session session,
+                    @Nullable RequestTrace trace,
                     @Nonnull RemoteRepository repository,
                     @Nonnull Collection<ProducedArtifact> artifacts,
                     int retryFailedDeploymentCount) {
-                super(session);
+                super(session, trace);
                 this.repository = requireNonNull(repository, "repository cannot be null");
                 this.artifacts = List.copyOf(requireNonNull(artifacts, "artifacts cannot be null"));
                 this.retryFailedDeploymentCount = retryFailedDeploymentCount;
@@ -136,6 +143,14 @@ public Collection<ProducedArtifact> getArtifacts() {
             public int getRetryFailedDeploymentCount() {
                 return retryFailedDeploymentCount;
             }
+
+            @Override
+            public String toString() {
+                return "ArtifactDeployerRequest[" + "repository="
+                        + repository + ", artifacts="
+                        + artifacts + ", retryFailedDeploymentCount="
+                        + retryFailedDeploymentCount + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java
index 378eed1608..c162f42093 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java
@@ -23,6 +23,7 @@
 import org.apache.maven.api.annotations.Immutable;
 import org.apache.maven.api.annotations.Nonnull;
 import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
 
 import static java.util.Objects.requireNonNull;
 
@@ -33,10 +34,7 @@
  */
 @Experimental
 @Immutable
-public interface ArtifactFactoryRequest {
-
-    @Nonnull
-    Session getSession();
+public interface ArtifactFactoryRequest extends Request<Session> {
 
     String getGroupId();
 
@@ -87,6 +85,7 @@ static ArtifactFactoryRequestBuilder builder() {
     @NotThreadSafe
     class ArtifactFactoryRequestBuilder {
         private Session session;
+        private RequestTrace trace;
         private String groupId;
         private String artifactId;
         private String version;
@@ -101,6 +100,11 @@ public ArtifactFactoryRequestBuilder session(Session session) {
             return this;
         }
 
+        public ArtifactFactoryRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         public ArtifactFactoryRequestBuilder groupId(String groupId) {
             this.groupId = groupId;
             return this;
@@ -133,7 +137,7 @@ public ArtifactFactoryRequestBuilder type(String type) {
 
         public ArtifactFactoryRequest build() {
             return new DefaultArtifactFactoryRequest(
-                    session, groupId, artifactId, version, classifier, extension, type);
+                    session, trace, groupId, artifactId, version, classifier, extension, type);
         }
 
         private static class DefaultArtifactFactoryRequest extends BaseRequest<Session>
@@ -145,15 +149,17 @@ private static class DefaultArtifactFactoryRequest extends BaseRequest<Session>
             private final String extension;
             private final String type;
 
+            @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultArtifactFactoryRequest(
                     @Nonnull Session session,
+                    @Nullable RequestTrace trace,
                     String groupId,
                     String artifactId,
                     String version,
                     String classifier,
                     String extension,
                     String type) {
-                super(session);
+                super(session, trace);
                 this.groupId = groupId;
                 this.artifactId = artifactId;
                 this.version = version;
@@ -191,6 +197,17 @@ public String getExtension() {
             public String getType() {
                 return type;
             }
+
+            @Override
+            public String toString() {
+                return "ArtifactFactoryRequest[" + "groupId='"
+                        + groupId + '\'' + ", artifactId='"
+                        + artifactId + '\'' + ", version='"
+                        + version + '\'' + ", classifier='"
+                        + classifier + '\'' + ", extension='"
+                        + extension + '\'' + ", type='"
+                        + type + '\'' + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java
index badf60170d..7c3130aced 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java
@@ -39,10 +39,7 @@
  */
 @Experimental
 @Immutable
-public interface ArtifactInstallerRequest {
-
-    @Nonnull
-    Session getSession();
+public interface ArtifactInstallerRequest extends Request<Session> {
 
     @Nonnull
     Collection<ProducedArtifact> getArtifacts();
@@ -63,6 +60,7 @@ static ArtifactInstallerRequest build(Session session, Collection<ProducedArtifa
     @NotThreadSafe
     class ArtifactInstallerRequestBuilder {
         Session session;
+        RequestTrace trace;
         Collection<ProducedArtifact> artifacts = Collections.emptyList();
 
         ArtifactInstallerRequestBuilder() {}
@@ -73,6 +71,12 @@ public ArtifactInstallerRequestBuilder session(@Nonnull Session session) {
             return this;
         }
 
+        @Nonnull
+        public ArtifactInstallerRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         @Nonnull
         public ArtifactInstallerRequestBuilder artifacts(@Nullable Collection<ProducedArtifact> artifacts) {
             this.artifacts = artifacts != null ? artifacts : Collections.emptyList();
@@ -81,15 +85,18 @@ public ArtifactInstallerRequestBuilder artifacts(@Nullable Collection<ProducedAr
 
         @Nonnull
         public ArtifactInstallerRequest build() {
-            return new DefaultArtifactInstallerRequest(session, artifacts);
+            return new DefaultArtifactInstallerRequest(session, trace, artifacts);
         }
 
         static class DefaultArtifactInstallerRequest extends BaseRequest<Session> implements ArtifactInstallerRequest {
 
             private final Collection<ProducedArtifact> artifacts;
 
-            DefaultArtifactInstallerRequest(@Nonnull Session session, @Nonnull Collection<ProducedArtifact> artifacts) {
-                super(session);
+            DefaultArtifactInstallerRequest(
+                    @Nonnull Session session,
+                    @Nullable RequestTrace trace,
+                    @Nonnull Collection<ProducedArtifact> artifacts) {
+                super(session, trace);
                 this.artifacts = List.copyOf(requireNonNull(artifacts, "artifacts cannot be null"));
             }
 
@@ -98,6 +105,11 @@ static class DefaultArtifactInstallerRequest extends BaseRequest<Session> implem
             public Collection<ProducedArtifact> getArtifacts() {
                 return artifacts;
             }
+
+            @Override
+            public String toString() {
+                return "ArtifactInstallerRequest[" + "artifacts=" + artifacts + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
index ae937914e6..4651a07332 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
@@ -39,9 +39,7 @@
  */
 @Experimental
 @Immutable
-public interface ArtifactResolverRequest {
-    @Nonnull
-    Session getSession();
+public interface ArtifactResolverRequest extends Request<Session> {
 
     @Nonnull
     Collection<? extends ArtifactCoordinates> getCoordinates();
@@ -78,6 +76,7 @@ static ArtifactResolverRequest build(
     @NotThreadSafe
     class ArtifactResolverRequestBuilder {
         Session session;
+        RequestTrace trace;
         Collection<? extends ArtifactCoordinates> coordinates;
         List<RemoteRepository> repositories;
 
@@ -89,6 +88,12 @@ public ArtifactResolverRequestBuilder session(Session session) {
             return this;
         }
 
+        @Nonnull
+        public ArtifactResolverRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         @Nonnull
         public ArtifactResolverRequestBuilder coordinates(Collection<? extends ArtifactCoordinates> coordinates) {
             this.coordinates = coordinates;
@@ -103,7 +108,7 @@ public ArtifactResolverRequestBuilder repositories(List<RemoteRepository> reposi
 
         @Nonnull
         public ArtifactResolverRequest build() {
-            return new DefaultArtifactResolverRequest(session, coordinates, repositories);
+            return new DefaultArtifactResolverRequest(session, trace, coordinates, repositories);
         }
 
         private static class DefaultArtifactResolverRequest extends BaseRequest<Session>
@@ -116,9 +121,10 @@ private static class DefaultArtifactResolverRequest extends BaseRequest<Session>
 
             DefaultArtifactResolverRequest(
                     @Nonnull Session session,
+                    @Nullable RequestTrace trace,
                     @Nonnull Collection<? extends ArtifactCoordinates> coordinates,
                     @Nonnull List<RemoteRepository> repositories) {
-                super(session);
+                super(session, trace);
                 this.coordinates = List.copyOf(requireNonNull(coordinates, "coordinates cannot be null"));
                 this.repositories = repositories;
             }
@@ -134,6 +140,13 @@ public Collection<? extends ArtifactCoordinates> getCoordinates() {
             public List<RemoteRepository> getRepositories() {
                 return repositories;
             }
+
+            @Override
+            public String toString() {
+                return "ArtifactResolverRequest[" + "coordinates="
+                        + coordinates + ", repositories="
+                        + repositories + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java
index 74d6cacb5f..f00f7b2337 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java
@@ -33,7 +33,7 @@
  * @since 4.0.0
  */
 @Experimental
-public interface ArtifactResolverResult {
+public interface ArtifactResolverResult extends Result<ArtifactResolverRequest> {
     /**
      * @return {@link Artifact}
      */
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java
index 43bbf6e0b3..6bf2c31b22 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java
@@ -30,16 +30,26 @@
  * @since 4.0.0
  */
 @Experimental
-abstract class BaseRequest<S extends ProtoSession> {
+abstract class BaseRequest<S extends ProtoSession> implements Request<S> {
 
     private final S session;
+    private final RequestTrace trace;
 
     protected BaseRequest(@Nonnull S session) {
+        this(session, null);
+    }
+
+    protected BaseRequest(@Nonnull S session, RequestTrace trace) {
         this.session = requireNonNull(session, "session cannot be null");
+        this.trace = trace;
     }
 
     @Nonnull
     public S getSession() {
         return session;
     }
+
+    public RequestTrace getTrace() {
+        return trace;
+    }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinatesFactoryRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinatesFactoryRequest.java
index 7618aaa992..5bcf124711 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinatesFactoryRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinatesFactoryRequest.java
@@ -30,6 +30,7 @@
 import org.apache.maven.api.annotations.Immutable;
 import org.apache.maven.api.annotations.Nonnull;
 import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
 
 import static java.util.Objects.requireNonNull;
 
@@ -105,6 +106,7 @@ static DependencyCoordinatesFactoryRequestBuilder builder() {
     @NotThreadSafe
     class DependencyCoordinatesFactoryRequestBuilder {
         private Session session;
+        private RequestTrace trace;
         private String groupId;
         private String artifactId;
         private String version;
@@ -123,6 +125,11 @@ public DependencyCoordinatesFactoryRequestBuilder session(Session session) {
             return this;
         }
 
+        public DependencyCoordinatesFactoryRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         public DependencyCoordinatesFactoryRequestBuilder groupId(String groupId) {
             this.groupId = groupId;
             return this;
@@ -191,6 +198,7 @@ public DependencyCoordinatesFactoryRequestBuilder exclusion(Exclusion exclusion)
         public DependencyCoordinatesFactoryRequest build() {
             return new DefaultDependencyCoordinatesFactoryRequest(
                     session,
+                    trace,
                     groupId,
                     artifactId,
                     version,
@@ -219,6 +227,7 @@ private static class DefaultDependencyCoordinatesFactoryRequest extends BaseRequ
             @SuppressWarnings("checkstyle:ParameterNumber")
             private DefaultDependencyCoordinatesFactoryRequest(
                     @Nonnull Session session,
+                    @Nullable RequestTrace trace,
                     String groupId,
                     String artifactId,
                     String version,
@@ -229,7 +238,7 @@ private DefaultDependencyCoordinatesFactoryRequest(
                     String scope,
                     boolean optional,
                     Collection<Exclusion> exclusions) {
-                super(session);
+                super(session, trace);
                 this.groupId = groupId;
                 this.artifactId = artifactId;
                 this.version = version;
@@ -291,6 +300,21 @@ public boolean isOptional() {
             public Collection<Exclusion> getExclusions() {
                 return exclusions;
             }
+
+            @Override
+            public String toString() {
+                return "DependencyCoordinatesFactoryRequest[" + "groupId='"
+                        + groupId + '\'' + ", artifactId='"
+                        + artifactId + '\'' + ", version='"
+                        + version + '\'' + ", classifier='"
+                        + classifier + '\'' + ", extension='"
+                        + extension + '\'' + ", type='"
+                        + type + '\'' + ", coordinateString='"
+                        + coordinateString + '\'' + ", scope='"
+                        + scope + '\'' + ", optional="
+                        + optional + ", exclusions="
+                        + exclusions + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java
index 1a8d3529f1..532a9b6551 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java
@@ -52,7 +52,7 @@
  */
 @Experimental
 @Immutable
-public interface DependencyResolverRequest {
+public interface DependencyResolverRequest extends Request<Session> {
 
     enum RequestType {
         COLLECT,
@@ -60,9 +60,6 @@ enum RequestType {
         RESOLVE
     }
 
-    @Nonnull
-    Session getSession();
-
     @Nonnull
     RequestType getRequestType();
 
@@ -173,6 +170,7 @@ static DependencyResolverRequest build(
     class DependencyResolverRequestBuilder {
 
         Session session;
+        RequestTrace trace;
         RequestType requestType;
         Project project;
         Artifact rootArtifact;
@@ -192,6 +190,12 @@ public DependencyResolverRequestBuilder session(@Nonnull Session session) {
             return this;
         }
 
+        @Nonnull
+        public DependencyResolverRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         @Nonnull
         public DependencyResolverRequestBuilder requestType(@Nonnull RequestType requestType) {
             this.requestType = requestType;
@@ -350,6 +354,7 @@ public DependencyResolverRequestBuilder repositories(@Nonnull List<RemoteReposit
         public DependencyResolverRequest build() {
             return new DefaultDependencyResolverRequest(
                     session,
+                    trace,
                     requestType,
                     project,
                     rootArtifact,
@@ -364,6 +369,31 @@ public DependencyResolverRequest build() {
 
         static class DefaultDependencyResolverRequest extends BaseRequest<Session>
                 implements DependencyResolverRequest {
+
+            static final class AlwaysTrueFilter implements Predicate<PathType> {
+                @Override
+                public boolean test(PathType pathType) {
+                    return true;
+                }
+
+                @Override
+                public boolean equals(Object obj) {
+                    return obj instanceof AlwaysTrueFilter;
+                }
+
+                @Override
+                public int hashCode() {
+                    return AlwaysTrueFilter.class.hashCode();
+                }
+
+                @Override
+                public String toString() {
+                    return "AlwaysTrueFilter[]";
+                }
+            }
+
+            private static final Predicate<PathType> DEFAULT_FILTER = new AlwaysTrueFilter();
+
             private final RequestType requestType;
             private final Project project;
             private final Artifact rootArtifact;
@@ -385,6 +415,7 @@ static class DefaultDependencyResolverRequest extends BaseRequest<Session>
             @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultDependencyResolverRequest(
                     @Nonnull Session session,
+                    @Nullable RequestTrace trace,
                     @Nonnull RequestType requestType,
                     @Nullable Project project,
                     @Nullable Artifact rootArtifact,
@@ -395,7 +426,7 @@ static class DefaultDependencyResolverRequest extends BaseRequest<Session>
                     @Nullable PathScope pathScope,
                     @Nullable Predicate<PathType> pathTypeFilter,
                     @Nullable List<RemoteRepository> repositories) {
-                super(session);
+                super(session, trace);
                 this.requestType = requireNonNull(requestType, "requestType cannot be null");
                 this.project = project;
                 this.rootArtifact = rootArtifact;
@@ -405,7 +436,7 @@ static class DefaultDependencyResolverRequest extends BaseRequest<Session>
                         List.copyOf(requireNonNull(managedDependencies, "managedDependencies cannot be null"));
                 this.verbose = verbose;
                 this.pathScope = requireNonNull(pathScope, "pathScope cannot be null");
-                this.pathTypeFilter = (pathTypeFilter != null) ? pathTypeFilter : (t) -> true;
+                this.pathTypeFilter = (pathTypeFilter != null) ? pathTypeFilter : DEFAULT_FILTER;
                 this.repositories = repositories;
                 if (verbose && requestType != RequestType.COLLECT) {
                     throw new IllegalArgumentException("verbose cannot only be true when collecting dependencies");
@@ -468,10 +499,19 @@ public List<RemoteRepository> getRepositories() {
                 return repositories;
             }
 
-            @Nonnull
             @Override
             public String toString() {
-                return getRoot() + " -> " + getDependencies();
+                return "DependencyResolverRequest[" + "requestType="
+                        + requestType + ", project="
+                        + project + ", rootArtifact="
+                        + rootArtifact + ", root="
+                        + root + ", dependencies="
+                        + dependencies + ", managedDependencies="
+                        + managedDependencies + ", verbose="
+                        + verbose + ", pathScope="
+                        + pathScope + ", pathTypeFilter="
+                        + pathTypeFilter + ", repositories="
+                        + repositories + ']';
             }
         }
     }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java
index 7b7f920469..af53d280e2 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java
@@ -41,7 +41,7 @@
  * @see DependencyResolver#resolve(DependencyResolverRequest)
  */
 @Experimental
-public interface DependencyResolverResult {
+public interface DependencyResolverResult extends Result<DependencyResolverRequest> {
 
     /**
      * Gets the exceptions that occurred while building the dependency graph.
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
index 0b80828bc9..99d384fc93 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
@@ -42,7 +42,7 @@
  */
 @Experimental
 @Immutable
-public interface ModelBuilderRequest {
+public interface ModelBuilderRequest extends Request<Session> {
 
     /**
      * The possible request types for building a model.
@@ -87,9 +87,6 @@ enum RepositoryMerging {
         REQUEST_DOMINANT,
     }
 
-    @Nonnull
-    Session getSession();
-
     @Nonnull
     ModelSource getSource();
 
@@ -177,6 +174,7 @@ static ModelBuilderRequestBuilder builder(ModelBuilderRequest request) {
     @NotThreadSafe
     class ModelBuilderRequestBuilder {
         Session session;
+        RequestTrace trace;
         RequestType requestType;
         boolean locationTracking;
         boolean recursive;
@@ -194,6 +192,7 @@ class ModelBuilderRequestBuilder {
 
         ModelBuilderRequestBuilder(ModelBuilderRequest request) {
             this.session = request.getSession();
+            this.trace = request.getTrace();
             this.requestType = request.getRequestType();
             this.locationTracking = request.isLocationTracking();
             this.recursive = request.isRecursive();
@@ -213,6 +212,11 @@ public ModelBuilderRequestBuilder session(Session session) {
             return this;
         }
 
+        public ModelBuilderRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         public ModelBuilderRequestBuilder requestType(RequestType requestType) {
             this.requestType = requestType;
             return this;
@@ -276,6 +280,7 @@ public ModelBuilderRequestBuilder lifecycleBindingsInjector(ModelTransformer lif
         public ModelBuilderRequest build() {
             return new DefaultModelBuilderRequest(
                     session,
+                    trace,
                     requestType,
                     locationTracking,
                     recursive,
@@ -307,6 +312,7 @@ private static class DefaultModelBuilderRequest extends BaseRequest<Session> imp
             @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultModelBuilderRequest(
                     @Nonnull Session session,
+                    @Nullable RequestTrace trace,
                     @Nonnull RequestType requestType,
                     boolean locationTracking,
                     boolean recursive,
@@ -319,7 +325,7 @@ private static class DefaultModelBuilderRequest extends BaseRequest<Session> imp
                     RepositoryMerging repositoryMerging,
                     List<RemoteRepository> repositories,
                     ModelTransformer lifecycleBindingsInjector) {
-                super(session);
+                super(session, trace);
                 this.requestType = requireNonNull(requestType, "requestType cannot be null");
                 this.locationTracking = locationTracking;
                 this.recursive = recursive;
@@ -395,6 +401,23 @@ public List<RemoteRepository> getRepositories() {
             public ModelTransformer getLifecycleBindingsInjector() {
                 return lifecycleBindingsInjector;
             }
+
+            @Override
+            public String toString() {
+                return "ModelBuilderRequest[" + "requestType="
+                        + requestType + ", locationTracking="
+                        + locationTracking + ", recursive="
+                        + recursive + ", source="
+                        + source + ", profiles="
+                        + profiles + ", activeProfileIds="
+                        + activeProfileIds + ", inactiveProfileIds="
+                        + inactiveProfileIds + ", systemProperties="
+                        + systemProperties + ", userProperties="
+                        + userProperties + ", repositoryMerging="
+                        + repositoryMerging + ", repositories="
+                        + repositories + ", lifecycleBindingsInjector="
+                        + lifecycleBindingsInjector + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java
index df38a5a62d..e4bec3a4d5 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderResult.java
@@ -31,7 +31,7 @@
  * @since 4.0.0
  */
 @Experimental
-public interface ModelBuilderResult {
+public interface ModelBuilderResult extends Result<ModelBuilderRequest> {
 
     /**
      * Gets the source from which the model was read.
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
index feedd5103b..e0e9eee5b5 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
@@ -42,10 +42,7 @@
  */
 @Experimental
 @Immutable
-public interface ProjectBuilderRequest {
-
-    @Nonnull
-    Session getSession();
+public interface ProjectBuilderRequest extends Request<Session> {
 
     @Nonnull
     Optional<Path> getPath();
@@ -86,6 +83,7 @@ static ProjectBuilderRequestBuilder builder() {
     @NotThreadSafe
     class ProjectBuilderRequestBuilder {
         Session session;
+        RequestTrace trace;
         Path path;
         Source source;
         boolean allowStubModel;
@@ -100,6 +98,11 @@ public ProjectBuilderRequestBuilder session(Session session) {
             return this;
         }
 
+        public ProjectBuilderRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         public ProjectBuilderRequestBuilder path(Path path) {
             this.path = path;
             return this;
@@ -122,7 +125,7 @@ public ProjectBuilderRequestBuilder repositories(List<RemoteRepository> reposito
 
         public ProjectBuilderRequest build() {
             return new DefaultProjectBuilderRequest(
-                    session, path, source, allowStubModel, recursive, processPlugins, repositories);
+                    session, trace, path, source, allowStubModel, recursive, processPlugins, repositories);
         }
 
         private static class DefaultProjectBuilderRequest extends BaseRequest<Session>
@@ -137,13 +140,14 @@ private static class DefaultProjectBuilderRequest extends BaseRequest<Session>
             @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultProjectBuilderRequest(
                     @Nonnull Session session,
+                    @Nullable RequestTrace trace,
                     @Nullable Path path,
                     @Nullable Source source,
                     boolean allowStubModel,
                     boolean recursive,
                     boolean processPlugins,
                     @Nullable List<RemoteRepository> repositories) {
-                super(session);
+                super(session, trace);
                 this.path = path;
                 this.source = source;
                 this.allowStubModel = allowStubModel;
@@ -183,6 +187,17 @@ public boolean isProcessPlugins() {
             public List<RemoteRepository> getRepositories() {
                 return repositories;
             }
+
+            @Override
+            public String toString() {
+                return "ProjectBuilderRequest[" + "path="
+                        + path + ", source="
+                        + source + ", allowStubModel="
+                        + allowStubModel + ", recursive="
+                        + recursive + ", processPlugins="
+                        + processPlugins + ", repositories="
+                        + repositories + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java
index 2247aa7b2e..1cc43440e9 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java
@@ -32,7 +32,7 @@
  * @since 4.0.0
  */
 @Experimental
-public interface ProjectBuilderResult {
+public interface ProjectBuilderResult extends Result<ProjectBuilderRequest> {
 
     /**
      * Gets the identifier of the project that could not be built. The general format of the identifier is {@code
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/Request.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Request.java
new file mode 100644
index 0000000000..28eecc94d8
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Request.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.ProtoSession;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ * Base interface for service requests in Maven. This interface defines the common contract
+ * for all request types within the Maven service layer, providing access to session context
+ * and request tracing capabilities.
+ *
+ * <p>Each request is associated with a {@link ProtoSession} that contains the configuration
+ * and context necessary for request processing, including:
+ * <ul>
+ *   <li>User and system properties for interpolation</li>
+ *   <li>Session start time information</li>
+ *   <li>Project directory structures</li>
+ * </ul>
+ *
+ * <p>Requests can optionally carry trace information through {@link RequestTrace} to support:
+ * <ul>
+ *   <li>Debugging and troubleshooting of request flows</li>
+ *   <li>Audit logging of operations</li>
+ *   <li>Performance monitoring of nested operations</li>
+ * </ul>
+ *
+ * <p>This interface is designed to be extended by specific request types that handle
+ * different Maven operations. All implementations must be immutable to ensure thread safety
+ * and predictable behavior in concurrent environments.
+ *
+ * @param <S> the type of ProtoSession associated with this request, allowing for
+ *           type-safe session handling in specific request implementations
+ *
+ * @see ProtoSession
+ * @see RequestTrace
+ * @see Result
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface Request<S extends ProtoSession> {
+
+    /**
+     * Returns the session associated with this request.
+     *
+     * @return the session instance, never {@code null}
+     */
+    @Nonnull
+    S getSession();
+
+    /**
+     * Returns the trace information associated with this request, if any.
+     * The trace provides context about the request's position in the operation
+     * hierarchy and can carry additional diagnostic information.
+     *
+     * @return the request trace, or {@code null} if no trace information is available
+     */
+    @Nullable
+    RequestTrace getTrace();
+
+    /**
+     * Returns a string representation of this request, used for debugging and logging purposes.
+     * The format should include the request type and any significant attributes that define the
+     * request's state.
+     *
+     * @return a string representation of this request, never {@code null}
+     */
+    @Override
+    @Nonnull
+    String toString();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/RequestTrace.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/RequestTrace.java
new file mode 100644
index 0000000000..6dafc3aeaf
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/RequestTrace.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ * Represents a hierarchical trace of nested requests within a session, enabling correlation between
+ * session events and their originating operations in the application code. The trace structure
+ * supports the following key features:
+ *
+ * <ul>
+ *   <li>Maintains parent-child relationships between requests to track operation nesting</li>
+ *   <li>Carries contextual data describing the current request or operation</li>
+ *   <li>Supports both internal session operations and client-provided trace information</li>
+ * </ul>
+ *
+ * <p>For internal session operations, the trace typically contains {@code *Request} objects
+ * that represent the current processing state. Client code can also create traces with
+ * application-specific data to provide context when invoking session methods.</p>
+ *
+ * <p>This trace information is particularly useful for:</p>
+ * <ul>
+ *   <li>Debugging and troubleshooting request flows</li>
+ *   <li>Audit logging of session operations</li>
+ *   <li>Performance monitoring of nested operations</li>
+ * </ul>
+ *
+ * @param context The context identifier for this request trace, helping to identify the scope or purpose
+ *                of the request. May be null if no specific context is needed.
+ * @param parent The parent request trace that led to this request, establishing the chain of nested
+ *               operations. May be null for top-level requests.
+ * @param data Additional data associated with this request trace, typically containing the actual request
+ *             object being processed or any application-specific state information. May be null if no
+ *             additional data is needed.
+ */
+public record RequestTrace(@Nullable String context, @Nullable RequestTrace parent, @Nullable Object data) {
+
+    public static final String CONTEXT_PLUGIN = "plugin";
+    public static final String CONTEXT_PROJECT = "project";
+    public static final String CONTEXT_BOOTSTRAP = "bootstrap";
+
+    public RequestTrace(RequestTrace parent, Object data) {
+        this(parent != null ? parent.context() : null, parent, data);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Result.java
similarity index 53%
copy from api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java
copy to api/maven-api-core/src/main/java/org/apache/maven/api/services/Result.java
index c05e244767..65bdf97a91 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Result.java
@@ -19,31 +19,35 @@
 package org.apache.maven.api.services;
 
 import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
 import org.apache.maven.api.annotations.Nonnull;
-import org.apache.maven.api.settings.Settings;
 
 /**
+ * Base interface for service operation results in Maven. This interface defines the common contract
+ * for operation results, providing access to the original request that generated this result.
  *
+ * <p>Each result is linked to its originating {@link Request}, allowing for:
+ * <ul>
+ *   <li>Traceability between requests and their outcomes</li>
+ *   <li>Access to the session context used during processing</li>
+ *   <li>Correlation of results with their initiating parameters</li>
+ * </ul>
+ *
+ * @param <REQ> the type of Request that produced this result, ensuring type-safe
+ *              access to the original request parameters
+ *
+ * @see Request
  * @since 4.0.0
  */
 @Experimental
-public interface SettingsBuilderResult {
-
-    /**
-     * Gets the assembled settings.
-     *
-     * @return the assembled settings, never {@code null}
-     */
-    @Nonnull
-    Settings getEffectiveSettings();
+@Immutable
+public interface Result<REQ extends Request<?>> {
 
     /**
-     * Gets the problems that were encountered during the settings building. Note that only problems of severity
-     * {@link BuilderProblem.Severity#WARNING} and below are reported here. Problems with a higher severity level cause
-     * the settings builder to fail with a {@link SettingsBuilderException}.
+     * Returns the request that produced this result.
      *
-     * @return the problems that were encountered during the settings building, can be empty but never {@code null}
+     * @return the originating request instance, never {@code null}
      */
     @Nonnull
-    ProblemCollector<BuilderProblem> getProblems();
+    REQ getRequest();
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java
index 311f922362..57fe9cace4 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java
@@ -37,10 +37,7 @@
  */
 @Experimental
 @Immutable
-public interface SettingsBuilderRequest {
-
-    @Nonnull
-    ProtoSession getSession();
+public interface SettingsBuilderRequest extends Request<ProtoSession> {
 
     /**
      * Gets the installation settings source.
@@ -133,6 +130,7 @@ static SettingsBuilderRequestBuilder builder() {
     @NotThreadSafe
     class SettingsBuilderRequestBuilder {
         ProtoSession session;
+        RequestTrace trace;
         Source installationSettingsSource;
         Source projectSettingsSource;
         Source userSettingsSource;
@@ -143,6 +141,11 @@ public SettingsBuilderRequestBuilder session(ProtoSession session) {
             return this;
         }
 
+        public SettingsBuilderRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         public SettingsBuilderRequestBuilder installationSettingsSource(Source installationSettingsSource) {
             this.installationSettingsSource = installationSettingsSource;
             return this;
@@ -166,6 +169,7 @@ public SettingsBuilderRequestBuilder interpolationSource(UnaryOperator<String> i
         public SettingsBuilderRequest build() {
             return new DefaultSettingsBuilderRequest(
                     session,
+                    trace,
                     installationSettingsSource,
                     projectSettingsSource,
                     userSettingsSource,
@@ -182,11 +186,12 @@ private static class DefaultSettingsBuilderRequest extends BaseRequest<ProtoSess
             @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultSettingsBuilderRequest(
                     @Nonnull ProtoSession session,
+                    @Nullable RequestTrace trace,
                     @Nullable Source installationSettingsSource,
                     @Nullable Source projectSettingsSource,
                     @Nullable Source userSettingsSource,
                     @Nullable UnaryOperator<String> interpolationSource) {
-                super(session);
+                super(session, trace);
                 this.installationSettingsSource = installationSettingsSource;
                 this.projectSettingsSource = projectSettingsSource;
                 this.userSettingsSource = userSettingsSource;
@@ -216,6 +221,15 @@ public Optional<Source> getUserSettingsSource() {
             public Optional<UnaryOperator<String>> getInterpolationSource() {
                 return Optional.ofNullable(interpolationSource);
             }
+
+            @Override
+            public String toString() {
+                return "SettingsBuilderRequest[" + "installationSettingsSource="
+                        + installationSettingsSource + ", projectSettingsSource="
+                        + projectSettingsSource + ", userSettingsSource="
+                        + userSettingsSource + ", interpolationSource="
+                        + interpolationSource + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java
index c05e244767..37b6213da2 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java
@@ -27,7 +27,7 @@
  * @since 4.0.0
  */
 @Experimental
-public interface SettingsBuilderResult {
+public interface SettingsBuilderResult extends Result<SettingsBuilderRequest> {
 
     /**
      * Gets the assembled settings.
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java
index ea7c5ab912..9eca5b1310 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java
@@ -35,9 +35,7 @@
  * @since 4.0.0
  */
 @Experimental
-public interface ToolchainsBuilderRequest {
-    @Nonnull
-    ProtoSession getSession();
+public interface ToolchainsBuilderRequest extends Request<ProtoSession> {
 
     /**
      * Gets the installation Toolchains source.
@@ -93,6 +91,7 @@ static ToolchainsBuilderRequestBuilder builder() {
     @NotThreadSafe
     class ToolchainsBuilderRequestBuilder {
         ProtoSession session;
+        RequestTrace trace;
         Source installationToolchainsSource;
         Source userToolchainsSource;
 
@@ -101,6 +100,11 @@ public ToolchainsBuilderRequestBuilder session(ProtoSession session) {
             return this;
         }
 
+        public ToolchainsBuilderRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         public ToolchainsBuilderRequestBuilder installationToolchainsSource(Source installationToolchainsSource) {
             this.installationToolchainsSource = installationToolchainsSource;
             return this;
@@ -113,7 +117,7 @@ public ToolchainsBuilderRequestBuilder userToolchainsSource(Source userToolchain
 
         public ToolchainsBuilderRequest build() {
             return new ToolchainsBuilderRequestBuilder.DefaultToolchainsBuilderRequest(
-                    session, installationToolchainsSource, userToolchainsSource);
+                    session, trace, installationToolchainsSource, userToolchainsSource);
         }
 
         private static class DefaultToolchainsBuilderRequest extends BaseRequest<ProtoSession>
@@ -124,9 +128,10 @@ private static class DefaultToolchainsBuilderRequest extends BaseRequest<ProtoSe
             @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultToolchainsBuilderRequest(
                     @Nonnull ProtoSession session,
+                    @Nullable RequestTrace trace,
                     @Nullable Source installationToolchainsSource,
                     @Nullable Source userToolchainsSource) {
-                super(session);
+                super(session, trace);
                 this.installationToolchainsSource = installationToolchainsSource;
                 this.userToolchainsSource = userToolchainsSource;
             }
@@ -142,6 +147,13 @@ public Optional<Source> getInstallationToolchainsSource() {
             public Optional<Source> getUserToolchainsSource() {
                 return Optional.ofNullable(userToolchainsSource);
             }
+
+            @Override
+            public String toString() {
+                return "ToolchainsBuilderRequest[" + "installationToolchainsSource="
+                        + installationToolchainsSource + ", userToolchainsSource="
+                        + userToolchainsSource + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderResult.java
index d48d45bd79..3cf06a7397 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderResult.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderResult.java
@@ -27,7 +27,7 @@
  * @since 4.0.0
  */
 @Experimental
-public interface ToolchainsBuilderResult {
+public interface ToolchainsBuilderResult extends Result<ToolchainsBuilderRequest> {
     /**
      * Gets the assembled toolchains.
      *
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java
index d563091dbe..3ab8a89b1e 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java
@@ -35,10 +35,7 @@
  * @since 4.0.0
  */
 @Experimental
-public interface VersionRangeResolverRequest {
-
-    @Nonnull
-    Session getSession();
+public interface VersionRangeResolverRequest extends Request<Session> {
 
     @Nonnull
     ArtifactCoordinates getArtifactCoordinates();
@@ -72,6 +69,7 @@ static VersionResolverRequestBuilder builder() {
     @NotThreadSafe
     class VersionResolverRequestBuilder {
         Session session;
+        RequestTrace trace;
         ArtifactCoordinates artifactCoordinates;
         List<RemoteRepository> repositories;
 
@@ -80,6 +78,11 @@ public VersionResolverRequestBuilder session(Session session) {
             return this;
         }
 
+        public VersionResolverRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         public VersionResolverRequestBuilder artifactCoordinates(ArtifactCoordinates artifactCoordinates) {
             this.artifactCoordinates = artifactCoordinates;
             return this;
@@ -91,7 +94,7 @@ public VersionResolverRequestBuilder repositories(List<RemoteRepository> reposit
         }
 
         public VersionRangeResolverRequest build() {
-            return new DefaultVersionResolverRequest(session, artifactCoordinates, repositories);
+            return new DefaultVersionResolverRequest(session, trace, artifactCoordinates, repositories);
         }
 
         private static class DefaultVersionResolverRequest extends BaseRequest<Session>
@@ -102,9 +105,10 @@ private static class DefaultVersionResolverRequest extends BaseRequest<Session>
             @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultVersionResolverRequest(
                     @Nonnull Session session,
+                    @Nullable RequestTrace trace,
                     @Nonnull ArtifactCoordinates artifactCoordinates,
                     @Nullable List<RemoteRepository> repositories) {
-                super(session);
+                super(session, trace);
                 this.artifactCoordinates = artifactCoordinates;
                 this.repositories = repositories;
             }
@@ -120,6 +124,13 @@ public ArtifactCoordinates getArtifactCoordinates() {
             public List<RemoteRepository> getRepositories() {
                 return repositories;
             }
+
+            @Override
+            public String toString() {
+                return "VersionResolverRequest[" + "artifactCoordinates="
+                        + artifactCoordinates + ", repositories="
+                        + repositories + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverResult.java
index e0a5f83485..798190c0a0 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverResult.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverResult.java
@@ -36,7 +36,7 @@
  * @since 4.0.0
  */
 @Experimental
-public interface VersionRangeResolverResult {
+public interface VersionRangeResolverResult extends Result<VersionRangeResolverRequest> {
 
     /**
      * Gets the exceptions that occurred while resolving the version range.
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java
index 71a9a558eb..f2751d0c0c 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java
@@ -35,10 +35,7 @@
  * @since 4.0.0
  */
 @Experimental
-public interface VersionResolverRequest {
-
-    @Nonnull
-    Session getSession();
+public interface VersionResolverRequest extends Request<Session> {
 
     @Nonnull
     ArtifactCoordinates getArtifactCoordinates();
@@ -74,6 +71,7 @@ static VersionResolverRequestBuilder builder() {
     @NotThreadSafe
     class VersionResolverRequestBuilder {
         Session session;
+        RequestTrace trace;
         ArtifactCoordinates artifactCoordinates;
         List<RemoteRepository> repositories;
 
@@ -82,6 +80,11 @@ public VersionResolverRequestBuilder session(Session session) {
             return this;
         }
 
+        public VersionResolverRequestBuilder trace(RequestTrace trace) {
+            this.trace = trace;
+            return this;
+        }
+
         public VersionResolverRequestBuilder artifactCoordinates(ArtifactCoordinates artifactCoordinates) {
             this.artifactCoordinates = artifactCoordinates;
             return this;
@@ -93,7 +96,7 @@ public VersionResolverRequestBuilder repositories(List<RemoteRepository> reposit
         }
 
         public VersionResolverRequest build() {
-            return new DefaultVersionResolverRequest(session, artifactCoordinates, repositories);
+            return new DefaultVersionResolverRequest(session, trace, artifactCoordinates, repositories);
         }
 
         private static class DefaultVersionResolverRequest extends BaseRequest<Session>
@@ -104,9 +107,10 @@ private static class DefaultVersionResolverRequest extends BaseRequest<Session>
             @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultVersionResolverRequest(
                     @Nonnull Session session,
+                    @Nullable RequestTrace trace,
                     @Nonnull ArtifactCoordinates artifactCoordinates,
                     @Nullable List<RemoteRepository> repositories) {
-                super(session);
+                super(session, trace);
                 this.artifactCoordinates = artifactCoordinates;
                 this.repositories = repositories;
             }
@@ -122,6 +126,13 @@ public ArtifactCoordinates getArtifactCoordinates() {
             public List<RemoteRepository> getRepositories() {
                 return repositories;
             }
+
+            @Override
+            public String toString() {
+                return "VersionResolverRequest[" + "artifactCoordinates="
+                        + artifactCoordinates + ", repositories="
+                        + repositories + ']';
+            }
         }
     }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverResult.java
index 2897183e8c..5b9e61b40d 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverResult.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverResult.java
@@ -31,7 +31,7 @@
  * @since 4.0.0
  */
 @Experimental
-public interface VersionResolverResult {
+public interface VersionResolverResult extends Result<VersionResolverRequest> {
 
     @Nonnull
     List<Exception> getExceptions();
diff --git a/api/maven-api-core/src/test/java/org/apache/maven/api/services/RequestImplementationTest.java b/api/maven-api-core/src/test/java/org/apache/maven/api/services/RequestImplementationTest.java
new file mode 100644
index 0000000000..61dc77c2e9
--- /dev/null
+++ b/api/maven-api-core/src/test/java/org/apache/maven/api/services/RequestImplementationTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.maven.api.ArtifactCoordinates;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Session;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+
+class RequestImplementationTest {
+
+    @Test
+    void testArtifactResolverRequestEquality() {
+        Session session = mock(Session.class);
+        ArtifactCoordinates coords1 = mock(ArtifactCoordinates.class);
+        ArtifactCoordinates coords2 = mock(ArtifactCoordinates.class);
+        RemoteRepository repo1 = mock(RemoteRepository.class);
+        RemoteRepository repo2 = mock(RemoteRepository.class);
+
+        List<RemoteRepository> repositories1 = Arrays.asList(repo1, repo2);
+        List<RemoteRepository> repositories2 = Arrays.asList(repo1, repo2);
+
+        ArtifactResolverRequest.ArtifactResolverRequestBuilder builder = ArtifactResolverRequest.builder();
+
+        ArtifactResolverRequest request1 = builder.session(session)
+                .coordinates(Arrays.asList(coords1, coords2))
+                .repositories(repositories1)
+                .build();
+
+        ArtifactResolverRequest request2 = builder.session(session)
+                .coordinates(Arrays.asList(coords1, coords2))
+                .repositories(repositories2)
+                .build();
+
+        ArtifactResolverRequest request3 = builder.session(session)
+                .coordinates(Arrays.asList(coords2, coords1)) // Different order
+                .repositories(repositories1)
+                .build();
+
+        // Test toString
+        String toString = request1.toString();
+        assertTrue(toString.contains("coordinates="));
+        assertTrue(toString.contains("repositories="));
+    }
+
+    @Test
+    void testRequestTraceIntegration() {
+        Session session = mock(Session.class);
+        RequestTrace trace = new RequestTrace("test-context", null, "test-data");
+
+        ArtifactInstallerRequest request =
+                ArtifactInstallerRequest.builder().session(session).trace(trace).build();
+
+        assertEquals(trace, request.getTrace());
+        assertEquals(session, request.getSession());
+    }
+}
diff --git a/api/maven-api-core/src/test/java/org/apache/maven/api/services/RequestTraceTest.java b/api/maven-api-core/src/test/java/org/apache/maven/api/services/RequestTraceTest.java
new file mode 100644
index 0000000000..4172a15d57
--- /dev/null
+++ b/api/maven-api-core/src/test/java/org/apache/maven/api/services/RequestTraceTest.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class RequestTraceTest {
+
+    @Test
+    void testRequestTraceCreation() {
+        RequestTrace parentTrace = new RequestTrace("parent-context", null, "parent-data");
+        RequestTrace childTrace = new RequestTrace("child-context", parentTrace, "child-data");
+
+        assertEquals("parent-context", parentTrace.context());
+        assertNull(parentTrace.parent());
+        assertEquals("parent-data", parentTrace.data());
+
+        assertEquals("child-context", childTrace.context());
+        assertSame(parentTrace, childTrace.parent());
+        assertEquals("child-data", childTrace.data());
+    }
+
+    @Test
+    void testRequestTraceWithParentContextInheritance() {
+        RequestTrace parentTrace = new RequestTrace("parent-context", null, "parent-data");
+        RequestTrace childTrace = new RequestTrace(parentTrace, "child-data");
+
+        assertEquals("parent-context", parentTrace.context());
+        assertEquals("parent-context", childTrace.context());
+        assertEquals("child-data", childTrace.data());
+    }
+
+    @Test
+    void testPredefinedContexts() {
+        assertEquals("plugin", RequestTrace.CONTEXT_PLUGIN);
+        assertEquals("project", RequestTrace.CONTEXT_PROJECT);
+        assertEquals("bootstrap", RequestTrace.CONTEXT_BOOTSTRAP);
+    }
+
+    @Test
+    void testNullValues() {
+        RequestTrace trace = new RequestTrace(null, null, null);
+        assertNull(trace.context());
+        assertNull(trace.parent());
+        assertNull(trace.data());
+    }
+
+    @Test
+    void testChainedTraces() {
+        RequestTrace root = new RequestTrace("root", null, "root-data");
+        RequestTrace level1 = new RequestTrace("level1", root, "level1-data");
+        RequestTrace level2 = new RequestTrace("level2", level1, "level2-data");
+        RequestTrace level3 = new RequestTrace(level2, "level3-data");
+
+        // Verify the chain
+        assertNull(root.parent());
+        assertEquals(root, level1.parent());
+        assertEquals(level1, level2.parent());
+        assertEquals(level2, level3.parent());
+
+        // Verify context inheritance
+        assertEquals("root", root.context());
+        assertEquals("level1", level1.context());
+        assertEquals("level2", level2.context());
+        assertEquals("level2", level3.context()); // Inherited from parent
+    }
+}
diff --git a/impl/maven-core/src/main/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListener.java b/impl/maven-core/src/main/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListener.java
index f1ae7295dc..a7379ae3cb 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListener.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListener.java
@@ -29,8 +29,8 @@
 import java.util.ListIterator;
 import java.util.Objects;
 
-import org.apache.maven.model.InputLocation;
-import org.apache.maven.model.Plugin;
+import org.apache.maven.api.model.InputLocation;
+import org.apache.maven.api.model.Plugin;
 import org.eclipse.aether.AbstractRepositoryListener;
 import org.eclipse.aether.RepositoryEvent;
 import org.eclipse.aether.RepositorySystemSession;
@@ -78,6 +78,8 @@ public void artifactResolved(RepositoryEvent event) {
                 artifactRequest = artifactRequestData;
             } else if (data instanceof Plugin pluginData) {
                 plugin = pluginData;
+            } else if (data instanceof org.apache.maven.model.Plugin pluginData) {
+                plugin = pluginData.getDelegate();
             }
             trace = trace.getParent();
         }
@@ -152,7 +154,7 @@ public void artifactResolved(RepositoryEvent event) {
         }
 
         if (trackingFile == null) {
-            return;
+            return; // parent or imported bom ?
         }
         try {
             Files.createDirectories(trackingDir);
diff --git a/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java b/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java
index f77536fc28..06690ec1b5 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java
@@ -43,6 +43,7 @@
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.impl.DefaultDependencyResolverResult;
 import org.apache.maven.impl.MappedCollection;
+import org.apache.maven.impl.RequestTraceHelper;
 import org.apache.maven.model.building.ModelProblem;
 import org.apache.maven.model.building.ModelSource2;
 import org.apache.maven.project.DefaultProjectBuildingRequest;
@@ -67,6 +68,7 @@ public DefaultProjectBuilder(org.apache.maven.project.ProjectBuilder builder) {
     public ProjectBuilderResult build(ProjectBuilderRequest request)
             throws ProjectBuilderException, IllegalArgumentException {
         InternalMavenSession session = InternalMavenSession.from(request.getSession());
+        RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(request.getSession(), request);
         try {
             List<ArtifactRepository> repositories = session.toArtifactRepositories(
                     request.getRepositories() != null ? request.getRepositories() : session.getRemoteRepositories());
@@ -87,6 +89,11 @@ public ProjectBuilderResult build(ProjectBuilderRequest request)
                 throw new IllegalArgumentException("Invalid request");
             }
             return new ProjectBuilderResult() {
+                @Override
+                public ProjectBuilderRequest getRequest() {
+                    return request;
+                }
+
                 @Nonnull
                 @Override
                 public String getProjectId() {
@@ -175,11 +182,14 @@ public Severity getSeverity() {
                 public Optional<DependencyResolverResult> getDependencyResolverResult() {
                     return Optional.ofNullable(res.getDependencyResolutionResult())
                             .map(r -> new DefaultDependencyResolverResult(
-                                    null, r.getCollectionErrors(), session.getNode(r.getDependencyGraph()), 0));
+                                    // TODO: this should not be null
+                                    null, null, r.getCollectionErrors(), session.getNode(r.getDependencyGraph()), 0));
                 }
             };
         } catch (ProjectBuildingException e) {
             throw new ProjectBuilderException("Unable to build project", e);
+        } finally {
+            RequestTraceHelper.exit(trace);
         }
     }
 
diff --git a/impl/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java b/impl/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
index e40586fba5..16aee3db31 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
@@ -30,6 +30,8 @@
 
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.api.DependencyScope;
+import org.apache.maven.impl.InternalSession;
+import org.apache.maven.impl.RequestTraceHelper;
 import org.apache.maven.impl.resolver.RelocatedArtifact;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.Plugin;
@@ -70,7 +72,7 @@
 @Named
 @Singleton
 public class DefaultPluginDependenciesResolver implements PluginDependenciesResolver {
-    private static final String REPOSITORY_CONTEXT = "plugin";
+    private static final String REPOSITORY_CONTEXT = org.apache.maven.api.services.RequestTrace.CONTEXT_PLUGIN;
 
     private final Logger logger = LoggerFactory.getLogger(getClass());
 
@@ -187,7 +189,8 @@ private DependencyResult resolveInternal(
             List<RemoteRepository> repositories,
             RepositorySystemSession session)
             throws PluginResolutionException {
-        RequestTrace trace = RequestTrace.newChild(null, plugin);
+        InternalSession iSession = InternalSession.from(session);
+        RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(iSession, plugin.getDelegate());
 
         if (pluginArtifact == null) {
             pluginArtifact = toArtifact(plugin, session);
@@ -217,9 +220,9 @@ private DependencyResult resolveInternal(
             }
 
             DependencyRequest depRequest = new DependencyRequest(request, resolutionFilter);
-            depRequest.setTrace(trace);
+            depRequest.setTrace(trace.trace());
 
-            request.setTrace(RequestTrace.newChild(trace, depRequest));
+            request.setTrace(RequestTrace.newChild(trace.trace(), depRequest));
 
             node = repoSystem.collectDependencies(pluginSession, request).getRoot();
 
@@ -239,6 +242,8 @@ private DependencyResult resolveInternal(
                                     .flatMap(r -> r.getExceptions().stream()))
                     .collect(Collectors.toList());
             throw new PluginResolutionException(plugin, exceptions, e);
+        } finally {
+            RequestTraceHelper.exit(trace);
         }
     }
 }
diff --git a/impl/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java b/impl/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java
index 8bcea49685..c616533cea 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java
@@ -62,7 +62,7 @@
 @Named
 @Singleton
 public class DefaultPluginPrefixResolver implements PluginPrefixResolver {
-    private static final String REPOSITORY_CONTEXT = "plugin";
+    private static final String REPOSITORY_CONTEXT = org.apache.maven.api.services.RequestTrace.CONTEXT_PLUGIN;
 
     private final Logger logger = LoggerFactory.getLogger(getClass());
     private final BuildPluginManager pluginManager;
diff --git a/impl/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java b/impl/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java
index 9082b30887..b2afbb073e 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java
@@ -72,7 +72,7 @@
 @Named
 @Singleton
 public class DefaultPluginVersionResolver implements PluginVersionResolver {
-    private static final String REPOSITORY_CONTEXT = "plugin";
+    private static final String REPOSITORY_CONTEXT = org.apache.maven.api.services.RequestTrace.CONTEXT_PLUGIN;
 
     private static final Object CACHE_KEY = new Object();
 
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/AbstractSession.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/AbstractSession.java
index ade3a7dde8..117b81fa45 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/AbstractSession.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/AbstractSession.java
@@ -84,6 +84,7 @@
 import org.apache.maven.api.services.PathScopeRegistry;
 import org.apache.maven.api.services.ProjectScopeRegistry;
 import org.apache.maven.api.services.RepositoryFactory;
+import org.apache.maven.api.services.RequestTrace;
 import org.apache.maven.api.services.TypeRegistry;
 import org.apache.maven.api.services.VersionParser;
 import org.apache.maven.api.services.VersionRangeResolver;
@@ -900,4 +901,20 @@ public DependencyScope requireDependencyScope(String id) {
     public PathScope requirePathScope(String id) {
         return getService(PathScopeRegistry.class).require(id);
     }
+
+    @Override
+    public void setCurrentTrace(RequestTrace trace) {
+        getTraceHolder().set(trace);
+    }
+
+    @Override
+    public RequestTrace getCurrentTrace() {
+        return getTraceHolder().get();
+    }
+
+    @SuppressWarnings("unchecked")
+    private ThreadLocal<RequestTrace> getTraceHolder() {
+        org.eclipse.aether.SessionData data = session.getData();
+        return (ThreadLocal<RequestTrace>) data.computeIfAbsent(RequestTrace.class, ThreadLocal::new);
+    }
 }
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultArtifactResolver.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultArtifactResolver.java
index a64be28b86..b83d649206 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultArtifactResolver.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultArtifactResolver.java
@@ -51,6 +51,7 @@ public ArtifactResolverResult resolve(ArtifactResolverRequest request)
             throws ArtifactResolverException, IllegalArgumentException {
         nonNull(request, "request");
         InternalSession session = InternalSession.from(request.getSession());
+        RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(session, request);
         try {
             Map<DownloadedArtifact, Path> paths = new HashMap<>();
             ArtifactManager artifactManager = session.getService(ArtifactManager.class);
@@ -68,7 +69,8 @@ public ArtifactResolverResult resolve(ArtifactResolverRequest request)
                     DownloadedArtifact resolved = session.getArtifact(DownloadedArtifact.class, aetherArtifact);
                     paths.put(resolved, path);
                 } else {
-                    requests.add(new ArtifactRequest(aetherArtifact, repositories, null));
+                    requests.add(
+                            new ArtifactRequest(aetherArtifact, repositories, trace.context()).setTrace(trace.trace()));
                 }
             }
             if (!requests.isEmpty()) {
@@ -80,19 +82,29 @@ public ArtifactResolverResult resolve(ArtifactResolverRequest request)
                     paths.put(artifact, path);
                 }
             }
-            return new DefaultArtifactResolverResult(paths);
+            return new DefaultArtifactResolverResult(request, paths);
         } catch (ArtifactResolutionException e) {
             throw new ArtifactResolverException("Unable to resolve artifact: " + e.getMessage(), e);
+        } finally {
+            RequestTraceHelper.exit(trace);
         }
     }
 
     static class DefaultArtifactResolverResult implements ArtifactResolverResult {
+
+        final ArtifactResolverRequest request;
         final Map<DownloadedArtifact, Path> paths;
 
-        DefaultArtifactResolverResult(Map<DownloadedArtifact, Path> paths) {
+        DefaultArtifactResolverResult(ArtifactResolverRequest request, Map<DownloadedArtifact, Path> paths) {
+            this.request = request;
             this.paths = paths;
         }
 
+        @Override
+        public ArtifactResolverRequest getRequest() {
+            return request;
+        }
+
         @Override
         public Collection<DownloadedArtifact> getArtifacts() {
             return paths.keySet();
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolver.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolver.java
index 4b4fc43e51..984c2c90a9 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolver.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolver.java
@@ -75,58 +75,64 @@ public DependencyResolverResult collect(@Nonnull DependencyResolverRequest reque
             throws DependencyResolverException, IllegalArgumentException {
         nonNull(request, "request");
         InternalSession session = InternalSession.from(request.getSession());
+        RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(session, request);
+        try {
+            Artifact rootArtifact;
+            DependencyCoordinates root;
+            Collection<DependencyCoordinates> dependencies;
+            Collection<DependencyCoordinates> managedDependencies;
+            List<RemoteRepository> remoteRepositories;
+            if (request.getProject().isPresent()) {
+                Project project = request.getProject().get();
+                rootArtifact = project.getPomArtifact();
+                root = null;
+                dependencies = project.getDependencies();
+                managedDependencies = project.getManagedDependencies();
+                remoteRepositories = request.getRepositories() != null
+                        ? request.getRepositories()
+                        : session.getService(ProjectManager.class).getRemoteProjectRepositories(project);
+            } else {
+                rootArtifact = request.getRootArtifact().orElse(null);
+                root = request.getRoot().orElse(null);
+                dependencies = request.getDependencies();
+                managedDependencies = request.getManagedDependencies();
+                remoteRepositories =
+                        request.getRepositories() != null ? request.getRepositories() : session.getRemoteRepositories();
+            }
+            ResolutionScope resolutionScope = null;
+            if (request.getPathScope() != null) {
+                resolutionScope = session.getSession()
+                        .getScopeManager()
+                        .getResolutionScope(request.getPathScope().id())
+                        .orElseThrow();
+            }
+            CollectRequest collectRequest = new CollectRequest()
+                    .setRootArtifact(rootArtifact != null ? session.toArtifact(rootArtifact) : null)
+                    .setRoot(root != null ? session.toDependency(root, false) : null)
+                    .setDependencies(session.toDependencies(dependencies, false))
+                    .setManagedDependencies(session.toDependencies(managedDependencies, true))
+                    .setRepositories(session.toRepositories(remoteRepositories))
+                    .setRequestContext(trace.context())
+                    .setTrace(trace.trace());
+            collectRequest.setResolutionScope(resolutionScope);
 
-        Artifact rootArtifact;
-        DependencyCoordinates root;
-        Collection<DependencyCoordinates> dependencies;
-        Collection<DependencyCoordinates> managedDependencies;
-        List<RemoteRepository> remoteRepositories;
-        if (request.getProject().isPresent()) {
-            Project project = request.getProject().get();
-            rootArtifact = project.getPomArtifact();
-            root = null;
-            dependencies = project.getDependencies();
-            managedDependencies = project.getManagedDependencies();
-            remoteRepositories = request.getRepositories() != null
-                    ? request.getRepositories()
-                    : session.getService(ProjectManager.class).getRemoteProjectRepositories(project);
-        } else {
-            rootArtifact = request.getRootArtifact().orElse(null);
-            root = request.getRoot().orElse(null);
-            dependencies = request.getDependencies();
-            managedDependencies = request.getManagedDependencies();
-            remoteRepositories =
-                    request.getRepositories() != null ? request.getRepositories() : session.getRemoteRepositories();
-        }
-        ResolutionScope resolutionScope = null;
-        if (request.getPathScope() != null) {
-            resolutionScope = session.getSession()
-                    .getScopeManager()
-                    .getResolutionScope(request.getPathScope().id())
-                    .orElseThrow();
-        }
-        CollectRequest collectRequest = new CollectRequest()
-                .setRootArtifact(rootArtifact != null ? session.toArtifact(rootArtifact) : null)
-                .setRoot(root != null ? session.toDependency(root, false) : null)
-                .setDependencies(session.toDependencies(dependencies, false))
-                .setManagedDependencies(session.toDependencies(managedDependencies, true))
-                .setRepositories(session.toRepositories(remoteRepositories));
-        collectRequest.setResolutionScope(resolutionScope);
-
-        RepositorySystemSession systemSession = session.getSession();
-        if (request.getVerbose()) {
-            systemSession = new DefaultRepositorySystemSession(systemSession)
-                    .setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true)
-                    .setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true);
-        }
+            RepositorySystemSession systemSession = session.getSession();
+            if (request.getVerbose()) {
+                systemSession = new DefaultRepositorySystemSession(systemSession)
+                        .setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true)
+                        .setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true);
+            }
 
-        try {
-            final CollectResult result =
-                    session.getRepositorySystem().collectDependencies(systemSession, collectRequest);
-            return new DefaultDependencyResolverResult(
-                    null, result.getExceptions(), session.getNode(result.getRoot(), request.getVerbose()), 0);
-        } catch (DependencyCollectionException e) {
-            throw new DependencyResolverException("Unable to collect dependencies", e);
+            try {
+                final CollectResult result =
+                        session.getRepositorySystem().collectDependencies(systemSession, collectRequest);
+                return new DefaultDependencyResolverResult(
+                        null, null, result.getExceptions(), session.getNode(result.getRoot(), request.getVerbose()), 0);
+            } catch (DependencyCollectionException e) {
+                throw new DependencyResolverException("Unable to collect dependencies", e);
+            }
+        } finally {
+            RequestTraceHelper.exit(trace);
         }
     }
 
@@ -162,54 +168,60 @@ private static DependencyFilter getScopeDependencyFilter(PathScope scope) {
      */
     @Override
     public DependencyResolverResult resolve(DependencyResolverRequest request)
-            throws DependencyResolverException, DependencyResolverException, ArtifactResolverException {
+            throws DependencyResolverException, ArtifactResolverException {
         InternalSession session =
                 InternalSession.from(nonNull(request, "request").getSession());
-        DependencyResolverResult result;
-        DependencyResolverResult collectorResult = collect(request);
-        List<RemoteRepository> repositories = request.getRepositories() != null
-                ? request.getRepositories()
-                : request.getProject().isPresent()
-                        ? session.getService(ProjectManager.class)
-                                .getRemoteProjectRepositories(
-                                        request.getProject().get())
-                        : session.getRemoteRepositories();
-        if (request.getRequestType() == DependencyResolverRequest.RequestType.COLLECT) {
-            result = collectorResult;
-        } else {
-            List<Node> nodes = flatten(session, collectorResult.getRoot(), request.getPathScope());
-            List<ArtifactCoordinates> coordinates = nodes.stream()
-                    .map(Node::getDependency)
-                    .filter(Objects::nonNull)
-                    .map(Artifact::toCoordinates)
-                    .collect(Collectors.toList());
-            Predicate<PathType> filter = request.getPathTypeFilter();
-            if (request.getRequestType() == DependencyResolverRequest.RequestType.FLATTEN) {
-                DefaultDependencyResolverResult flattenResult = new DefaultDependencyResolverResult(
-                        null, collectorResult.getExceptions(), collectorResult.getRoot(), nodes.size());
-                for (Node node : nodes) {
-                    flattenResult.addNode(node);
-                }
-                result = flattenResult;
+        RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(session, request);
+        try {
+            DependencyResolverResult result;
+            DependencyResolverResult collectorResult = collect(request);
+            List<RemoteRepository> repositories = request.getRepositories() != null
+                    ? request.getRepositories()
+                    : request.getProject().isPresent()
+                            ? session.getService(ProjectManager.class)
+                                    .getRemoteProjectRepositories(
+                                            request.getProject().get())
+                            : session.getRemoteRepositories();
+            if (request.getRequestType() == DependencyResolverRequest.RequestType.COLLECT) {
+                result = collectorResult;
             } else {
-                PathModularizationCache cache = new PathModularizationCache(); // TODO: should be project-wide cache.
-                DefaultDependencyResolverResult resolverResult = new DefaultDependencyResolverResult(
-                        cache, collectorResult.getExceptions(), collectorResult.getRoot(), nodes.size());
-                ArtifactResolverResult artifactResolverResult =
-                        session.getService(ArtifactResolver.class).resolve(session, coordinates, repositories);
-                for (Node node : nodes) {
-                    Dependency d = node.getDependency();
-                    Path path = (d != null) ? artifactResolverResult.getPath(d) : null;
-                    try {
-                        resolverResult.addDependency(node, d, filter, path);
-                    } catch (IOException e) {
-                        throw cannotReadModuleInfo(path, e);
+                List<Node> nodes = flatten(session, collectorResult.getRoot(), request.getPathScope());
+                List<ArtifactCoordinates> coordinates = nodes.stream()
+                        .map(Node::getDependency)
+                        .filter(Objects::nonNull)
+                        .map(Artifact::toCoordinates)
+                        .collect(Collectors.toList());
+                Predicate<PathType> filter = request.getPathTypeFilter();
+                if (request.getRequestType() == DependencyResolverRequest.RequestType.FLATTEN) {
+                    DefaultDependencyResolverResult flattenResult = new DefaultDependencyResolverResult(
+                            null, null, collectorResult.getExceptions(), collectorResult.getRoot(), nodes.size());
+                    for (Node node : nodes) {
+                        flattenResult.addNode(node);
+                    }
+                    result = flattenResult;
+                } else {
+                    PathModularizationCache cache =
+                            new PathModularizationCache(); // TODO: should be project-wide cache.
+                    DefaultDependencyResolverResult resolverResult = new DefaultDependencyResolverResult(
+                            null, cache, collectorResult.getExceptions(), collectorResult.getRoot(), nodes.size());
+                    ArtifactResolverResult artifactResolverResult =
+                            session.getService(ArtifactResolver.class).resolve(session, coordinates, repositories);
+                    for (Node node : nodes) {
+                        Dependency d = node.getDependency();
+                        Path path = (d != null) ? artifactResolverResult.getPath(d) : null;
+                        try {
+                            resolverResult.addDependency(node, d, filter, path);
+                        } catch (IOException e) {
+                            throw cannotReadModuleInfo(path, e);
+                        }
                     }
+                    result = resolverResult;
                 }
-                result = resolverResult;
             }
+            return result;
+        } finally {
+            RequestTraceHelper.exit(trace);
         }
-        return result;
     }
 
     private static DependencyResolverException cannotReadModuleInfo(final Path path, final IOException cause) {
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolverResult.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolverResult.java
index 9464ed7f11..fa7ace6e0d 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolverResult.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolverResult.java
@@ -52,6 +52,10 @@
  * @see DefaultDependencyResolver#resolve(DependencyResolverRequest)
  */
 public class DefaultDependencyResolverResult implements DependencyResolverResult {
+    /**
+     * The corresponding request.
+     */
+    private final DependencyResolverRequest request;
     /**
      * The exceptions that occurred while building the dependency graph.
      */
@@ -97,13 +101,19 @@ public class DefaultDependencyResolverResult implements DependencyResolverResult
      * Creates an initially empty result. Callers should add path elements by calls
      * to {@link #addDependency(Node, Dependency, Predicate, Path)}.
      *
+     * @param request the corresponding request
      * @param cache cache of module information about each dependency
      * @param exceptions the exceptions that occurred while building the dependency graph
      * @param root the root node of the dependency graph
      * @param count estimated number of dependencies
      */
     public DefaultDependencyResolverResult(
-            PathModularizationCache cache, List<Exception> exceptions, Node root, int count) {
+            DependencyResolverRequest request,
+            PathModularizationCache cache,
+            List<Exception> exceptions,
+            Node root,
+            int count) {
+        this.request = request;
         this.cache = cache;
         this.exceptions = exceptions;
         this.root = root;
@@ -333,6 +343,11 @@ private Path findArtifactPath(String group, String artifact) throws IOException
         return null;
     }
 
+    @Override
+    public DependencyResolverRequest getRequest() {
+        return request;
+    }
+
     @Override
     public List<Exception> getExceptions() {
         return exceptions;
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java
index 175eb7bc15..6924bb15ba 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSettingsBuilder.java
@@ -135,7 +135,7 @@ public SettingsBuilderResult build(SettingsBuilderRequest request) throws Settin
             throw new SettingsBuilderException("Error building settings", problems);
         }
 
-        return new DefaultSettingsBuilderResult(effective, problems);
+        return new DefaultSettingsBuilderResult(request, effective, problems);
     }
 
     private Settings readSettings(
@@ -330,15 +330,24 @@ public org.apache.maven.api.model.Profile convert(Profile profile) {
      */
     static class DefaultSettingsBuilderResult implements SettingsBuilderResult {
 
+        private final SettingsBuilderRequest request;
+
         private final Settings effectiveSettings;
 
         private final ProblemCollector<BuilderProblem> problems;
 
-        DefaultSettingsBuilderResult(Settings effectiveSettings, ProblemCollector<BuilderProblem> problems) {
+        DefaultSettingsBuilderResult(
+                SettingsBuilderRequest request, Settings effectiveSettings, ProblemCollector<BuilderProblem> problems) {
+            this.request = request;
             this.effectiveSettings = effectiveSettings;
             this.problems = (problems != null) ? problems : ProblemCollector.empty();
         }
 
+        @Override
+        public SettingsBuilderRequest getRequest() {
+            return request;
+        }
+
         @Override
         public Settings getEffectiveSettings() {
             return effectiveSettings;
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultToolchainsBuilder.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultToolchainsBuilder.java
index f2ce5abd5f..2d3360fc6e 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultToolchainsBuilder.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultToolchainsBuilder.java
@@ -78,7 +78,7 @@ public ToolchainsBuilderResult build(ToolchainsBuilderRequest request) throws To
             throw new ToolchainsBuilderException("Error building toolchains", problems);
         }
 
-        return new DefaultToolchainsBuilderResult(effective, problems);
+        return new DefaultToolchainsBuilderResult(request, effective, problems);
     }
 
     private PersistedToolchains readToolchains(
@@ -162,16 +162,26 @@ private PersistedToolchains interpolate(
      */
     static class DefaultToolchainsBuilderResult implements ToolchainsBuilderResult {
 
+        private final ToolchainsBuilderRequest request;
+
         private final PersistedToolchains effectiveToolchains;
 
         private final ProblemCollector<BuilderProblem> problems;
 
         DefaultToolchainsBuilderResult(
-                PersistedToolchains effectiveToolchains, ProblemCollector<BuilderProblem> problems) {
+                ToolchainsBuilderRequest request,
+                PersistedToolchains effectiveToolchains,
+                ProblemCollector<BuilderProblem> problems) {
+            this.request = request;
             this.effectiveToolchains = effectiveToolchains;
             this.problems = (problems != null) ? problems : ProblemCollector.empty();
         }
 
+        @Override
+        public ToolchainsBuilderRequest getRequest() {
+            return request;
+        }
+
         @Override
         public PersistedToolchains getEffectiveToolchains() {
             return effectiveToolchains;
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionRangeResolver.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionRangeResolver.java
index 74c2f75b13..a189d4328a 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionRangeResolver.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionRangeResolver.java
@@ -58,22 +58,29 @@ public VersionRangeResolverResult resolve(VersionRangeResolverRequest request)
         requireNonNull(request, "request");
         InternalSession session = InternalSession.from(request.getSession());
 
+        RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(session, request);
         try {
             VersionRangeResult res = repositorySystem.resolveVersionRange(
                     session.getSession(),
                     new VersionRangeRequest(
-                            session.toArtifact(request.getArtifactCoordinates()),
-                            session.toRepositories(
-                                    request.getRepositories() != null
-                                            ? request.getRepositories()
-                                            : session.getRemoteRepositories()),
-                            null));
+                                    session.toArtifact(request.getArtifactCoordinates()),
+                                    session.toRepositories(
+                                            request.getRepositories() != null
+                                                    ? request.getRepositories()
+                                                    : session.getRemoteRepositories()),
+                                    trace.context())
+                            .setTrace(trace.trace()));
 
             Map<String, ArtifactRepository> repos = res.getVersions().stream()
                     .filter(v -> res.getRepository(v) != null)
                     .collect(Collectors.toMap(v -> v.toString(), res::getRepository));
 
             return new VersionRangeResolverResult() {
+                @Override
+                public VersionRangeResolverRequest getRequest() {
+                    return request;
+                }
+
                 @Override
                 public List<Exception> getExceptions() {
                     return res.getExceptions();
@@ -98,6 +105,8 @@ public Optional<Repository> getRepository(Version version) {
             };
         } catch (VersionRangeResolutionException e) {
             throw new VersionRangeResolverException("Unable to resolve version range", e);
+        } finally {
+            RequestTraceHelper.exit(trace);
         }
     }
 }
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionResolver.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionResolver.java
index bc824cd256..a9b4ba4748 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionResolver.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionResolver.java
@@ -53,18 +53,24 @@ public VersionResolverResult resolve(VersionResolverRequest request) throws Vers
         nonNull(request, "request");
         InternalSession session = InternalSession.from(request.getSession());
 
+        RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(session, request);
         try {
-            VersionResult res = repositorySystem.resolveVersion(
-                    session.getSession(),
-                    new VersionRequest(
+            VersionRequest req = new VersionRequest(
                             session.toArtifact(request.getArtifactCoordinates()),
                             session.toRepositories(
                                     request.getRepositories() != null
                                             ? request.getRepositories()
                                             : session.getRemoteRepositories()),
-                            null));
+                            trace.context())
+                    .setTrace(trace.trace());
+            VersionResult res = repositorySystem.resolveVersion(session.getSession(), req);
 
             return new VersionResolverResult() {
+                @Override
+                public VersionResolverRequest getRequest() {
+                    return request;
+                }
+
                 @Override
                 public List<Exception> getExceptions() {
                     return res.getExceptions();
@@ -89,6 +95,8 @@ public Optional<Repository> getRepository() {
             };
         } catch (VersionResolutionException e) {
             throw new VersionResolverException("Unable to resolve version", e);
+        } finally {
+            RequestTraceHelper.exit(trace);
         }
     }
 }
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/InternalSession.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/InternalSession.java
index ce01aa50f9..fe8a44715b 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/InternalSession.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/InternalSession.java
@@ -30,6 +30,8 @@
 import org.apache.maven.api.RemoteRepository;
 import org.apache.maven.api.Session;
 import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.api.services.RequestTrace;
 import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
 
@@ -86,4 +88,26 @@ List<org.eclipse.aether.graph.Dependency> toDependencies(
     RepositorySystemSession getSession();
 
     RepositorySystem getRepositorySystem();
+
+    /**
+     * Sets the current request trace for the session.
+     * The request trace provides contextual information about the current operation
+     * being performed and can be used for debugging and monitoring purposes.
+     * The trace is stored in thread-local storage, allowing for concurrent operations
+     * with different traces.
+     *
+     * @param trace the trace to set as current, may be null to clear the trace
+     * @see RequestTraceHelper#enter(Session, Object) For the recommended way to manage traces
+     */
+    void setCurrentTrace(@Nullable RequestTrace trace);
+
+    /**
+     * Gets the current request trace for the session from thread-local storage.
+     * Each thread maintains its own trace context, ensuring thread-safety for
+     * concurrent operations.
+     *
+     * @return the current request trace, or null if no trace is set
+     * @see RequestTraceHelper#enter(Session, Object) For the recommended way to manage traces
+     */
+    RequestTrace getCurrentTrace();
 }
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/RequestTraceHelper.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/RequestTraceHelper.java
new file mode 100644
index 0000000000..44b54003f2
--- /dev/null
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/RequestTraceHelper.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.impl;
+
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.services.Request;
+import org.eclipse.aether.RequestTrace;
+import org.eclipse.aether.collection.CollectRequest;
+import org.eclipse.aether.collection.CollectStepData;
+import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.DependencyRequest;
+
+/**
+ * Helper class to manage request tracing for improved error logging in Maven's dependency resolution.
+ * This class provides utilities to:
+ * - Track request traces through Maven's dependency resolution process
+ * - Convert between Maven and Resolver trace formats
+ * - Generate human-readable interpretations of trace data
+ */
+public final class RequestTraceHelper {
+
+    /**
+     * Represents a resolver trace containing both Maven and Resolver-specific trace information
+     * @param session The current Maven session
+     * @param context The trace context
+     * @param trace The Resolver-specific trace
+     * @param mvnTrace The Maven-specific trace
+     */
+    public record ResolverTrace(
+            Session session, String context, RequestTrace trace, org.apache.maven.api.services.RequestTrace mvnTrace) {}
+
+    /**
+     * Creates a new trace entry and updates the session's current trace
+     * @param session The current Maven session
+     * @param data The data object to associate with the trace
+     * @return A new ResolverTrace containing both Maven and Resolver trace information
+     */
+    public static ResolverTrace enter(Session session, Object data) {
+        InternalSession iSession = InternalSession.from(session);
+        org.apache.maven.api.services.RequestTrace trace = data instanceof Request<?> req && req.getTrace() != null
+                ? req.getTrace()
+                : new org.apache.maven.api.services.RequestTrace(iSession.getCurrentTrace(), data);
+        iSession.setCurrentTrace(trace);
+        return new ResolverTrace(session, trace.context(), toResolver(trace), trace);
+    }
+
+    /**
+     * Restores the parent trace as the current trace in the session
+     * @param trace The current resolver trace to exit from
+     */
+    public static void exit(ResolverTrace trace) {
+        InternalSession iSession = InternalSession.from(trace.session());
+        iSession.setCurrentTrace(trace.mvnTrace().parent());
+    }
+
+    /**
+     * Converts a Resolver trace to a Maven trace
+     * @param context The context string for the new Maven trace
+     * @param trace The Resolver trace to convert
+     * @return A new Maven trace, or null if the input trace was null
+     */
+    public static org.apache.maven.api.services.RequestTrace toMaven(String context, RequestTrace trace) {
+        if (trace != null) {
+            return new org.apache.maven.api.services.RequestTrace(
+                    context, toMaven(context, trace.getParent()), trace.getData());
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Converts a Maven trace to a Resolver trace
+     * @param trace The Maven trace to convert
+     * @return A new Resolver trace, or null if the input trace was null
+     */
+    public static RequestTrace toResolver(org.apache.maven.api.services.RequestTrace trace) {
+        if (trace != null) {
+            return RequestTrace.newChild(toResolver(trace.parent()), trace.data());
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Creates a human-readable interpretation of a request trace
+     * @param detailed If true, includes additional details such as dependency paths
+     * @param requestTrace The trace to interpret
+     * @return A string describing the trace context and relevant details
+     */
+    public static String interpretTrace(boolean detailed, RequestTrace requestTrace) {
+        while (requestTrace != null) {
+            Object data = requestTrace.getData();
+            if (data instanceof DependencyRequest request) {
+                return "dependency resolution for " + request;
+            } else if (data instanceof CollectRequest request) {
+                return "dependency collection for " + request;
+            } else if (data instanceof CollectStepData stepData) {
+                String msg = "dependency collection step for " + stepData.getContext();
+                if (detailed) {
+                    msg += ". Path to offending node from root:\n";
+                    msg += stepData.getPath().stream()
+                            .map(n -> " -> " + n.toString())
+                            .collect(Collectors.joining("\n"));
+                    msg += "\n => " + stepData.getNode();
+                }
+                return msg;
+            } else if (data instanceof ArtifactDescriptorRequest request) {
+                return "artifact descriptor request for " + request.getArtifact();
+            } else if (data instanceof ArtifactRequest request) {
+                return "artifact request for " + request.getArtifact();
+            } else if (data instanceof org.apache.maven.api.model.Plugin plugin) {
+                return "plugin " + plugin.getId();
+            }
+            requestTrace = requestTrace.getParent();
+        }
+
+        return "n/a";
+    }
+}
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
index 84545c34e0..f05f505b3d 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
@@ -82,6 +82,7 @@
 import org.apache.maven.api.services.ModelSource;
 import org.apache.maven.api.services.ProblemCollector;
 import org.apache.maven.api.services.RepositoryFactory;
+import org.apache.maven.api.services.RequestTrace;
 import org.apache.maven.api.services.Source;
 import org.apache.maven.api.services.SuperPomProvider;
 import org.apache.maven.api.services.VersionParserException;
@@ -109,6 +110,8 @@
 import org.apache.maven.api.services.xml.XmlReaderRequest;
 import org.apache.maven.api.spi.ModelParserException;
 import org.apache.maven.api.spi.ModelTransformer;
+import org.apache.maven.impl.InternalSession;
+import org.apache.maven.impl.RequestTraceHelper;
 import org.apache.maven.impl.util.PhasingExecutor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -217,24 +220,30 @@ protected class ModelBuilderSessionImpl implements ModelBuilderSession {
          */
         @Override
         public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException {
-            // Create or derive a session based on the request
-            ModelBuilderSessionState session;
-            if (mainSession == null) {
-                mainSession = new ModelBuilderSessionState(request);
-                session = mainSession;
-            } else {
-                session = mainSession.derive(
-                        request, new DefaultModelBuilderResult(ProblemCollector.create(mainSession.session)));
-            }
-            // Build the request
-            if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_PROJECT) {
-                // build the build poms
-                session.buildBuildPom();
-            } else {
-                // simply build the effective model
-                session.buildEffectiveModel(new LinkedHashSet<>());
+            RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(request.getSession(), request);
+            try {
+                // Create or derive a session based on the request
+                ModelBuilderSessionState session;
+                if (mainSession == null) {
+                    mainSession = new ModelBuilderSessionState(request);
+                    session = mainSession;
+                } else {
+                    session = mainSession.derive(
+                            request,
+                            new DefaultModelBuilderResult(request, ProblemCollector.create(mainSession.session)));
+                }
+                // Build the request
+                if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_PROJECT) {
+                    // build the build poms
+                    session.buildBuildPom();
+                } else {
+                    // simply build the effective model
+                    session.buildEffectiveModel(new LinkedHashSet<>());
+                }
+                return session.result;
+            } finally {
+                RequestTraceHelper.exit(trace);
             }
-            return session.result;
         }
     }
 
@@ -260,7 +269,7 @@ protected class ModelBuilderSessionState implements ModelProblemCollector {
             this(
                     request.getSession(),
                     request,
-                    new DefaultModelBuilderResult(ProblemCollector.create(request.getSession())),
+                    new DefaultModelBuilderResult(request, ProblemCollector.create(request.getSession())),
                     request.getSession()
                             .getData()
                             .computeIfAbsent(SessionData.key(ModelCache.class), modelCacheFactory::newInstance),
@@ -302,7 +311,7 @@ private ModelBuilderSessionState(
         }
 
         ModelBuilderSessionState derive(ModelSource source) {
-            return derive(source, new DefaultModelBuilderResult(ProblemCollector.create(session)));
+            return derive(source, new DefaultModelBuilderResult(request, ProblemCollector.create(session)));
         }
 
         ModelBuilderSessionState derive(ModelSource source, DefaultModelBuilderResult result) {
@@ -313,7 +322,7 @@ ModelBuilderSessionState derive(ModelSource source, DefaultModelBuilderResult re
          * Creates a new session, sharing cached datas and propagating errors.
          */
         ModelBuilderSessionState derive(ModelBuilderRequest request) {
-            return derive(request, new DefaultModelBuilderResult(ProblemCollector.create(session)));
+            return derive(request, new DefaultModelBuilderResult(request, ProblemCollector.create(session)));
         }
 
         ModelBuilderSessionState derive(ModelBuilderRequest request, DefaultModelBuilderResult result) {
@@ -638,16 +647,21 @@ private void buildBuildPom() throws ModelBuilderException {
             // This is done through the phased executor
             var allResults = results(result).toList();
             List<RuntimeException> exceptions = new CopyOnWriteArrayList<>();
+            InternalSession session = InternalSession.from(this.session);
+            RequestTrace trace = session.getCurrentTrace();
             try (PhasingExecutor executor = createExecutor()) {
                 for (DefaultModelBuilderResult r : allResults) {
                     executor.execute(() -> {
                         ModelBuilderSessionState mbs = derive(r.getSource(), r);
+                        session.setCurrentTrace(trace);
                         try {
                             mbs.buildEffectiveModel(new LinkedHashSet<>());
                         } catch (ModelBuilderException e) {
                             // gathered with problem collector
                         } catch (RuntimeException t) {
                             exceptions.add(t);
+                        } finally {
+                            session.setCurrentTrace(null);
                         }
                     });
                 }
@@ -681,7 +695,7 @@ private void loadFromRoot(Path root, Path top) {
             try (PhasingExecutor executor = createExecutor()) {
                 DefaultModelBuilderResult r = Objects.equals(top, root)
                         ? result
-                        : new DefaultModelBuilderResult(ProblemCollector.create(session));
+                        : new DefaultModelBuilderResult(request, ProblemCollector.create(session));
                 loadFilePom(executor, top, root, Set.of(), r);
             }
             if (result.getFileModel() == null && !Objects.equals(top, root)) {
@@ -755,12 +769,21 @@ private void loadFilePom(
 
                     DefaultModelBuilderResult cr = Objects.equals(top, subprojectFile)
                             ? result
-                            : new DefaultModelBuilderResult(ProblemCollector.create(session));
+                            : new DefaultModelBuilderResult(request, ProblemCollector.create(session));
                     if (request.isRecursive()) {
                         r.getChildren().add(cr);
                     }
 
-                    executor.execute(() -> loadFilePom(executor, top, subprojectFile, concat(parents, pom), cr));
+                    InternalSession session = InternalSession.from(this.session);
+                    RequestTrace trace = session.getCurrentTrace();
+                    executor.execute(() -> {
+                        session.setCurrentTrace(trace);
+                        try {
+                            loadFilePom(executor, top, subprojectFile, concat(parents, pom), cr);
+                        } finally {
+                            session.setCurrentTrace(null);
+                        }
+                    });
                 }
             } catch (ModelBuilderException e) {
                 // gathered with problem collector
@@ -1881,12 +1904,17 @@ private static List<String> getSubprojects(Model activated) {
 
     @Override
     public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderException {
-        ModelBuilderSessionState build = new ModelBuilderSessionState(request);
-        Model model = build.readRawModel();
-        if (build.hasErrors()) {
-            throw build.newModelBuilderException();
+        RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(request.getSession(), request);
+        try {
+            ModelBuilderSessionState build = new ModelBuilderSessionState(request);
+            Model model = build.readRawModel();
+            if (build.hasErrors()) {
+                throw build.newModelBuilderException();
+            }
+            return model;
+        } finally {
+            RequestTraceHelper.exit(trace);
         }
-        return model;
     }
 
     static String getGroupId(Model model) {
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilderResult.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilderResult.java
index 89f4b7ae38..5f87b7d779 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilderResult.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilderResult.java
@@ -25,6 +25,7 @@
 
 import org.apache.maven.api.model.Model;
 import org.apache.maven.api.model.Profile;
+import org.apache.maven.api.services.ModelBuilderRequest;
 import org.apache.maven.api.services.ModelBuilderResult;
 import org.apache.maven.api.services.ModelProblem;
 import org.apache.maven.api.services.ModelSource;
@@ -34,6 +35,7 @@
  * Collects the output of the model builder.
  */
 class DefaultModelBuilderResult implements ModelBuilderResult {
+    private ModelBuilderRequest request;
     private ModelSource source;
     private Model fileModel;
     private Model rawModel;
@@ -44,10 +46,16 @@ class DefaultModelBuilderResult implements ModelBuilderResult {
     private final ProblemCollector<ModelProblem> problemCollector;
     private final List<DefaultModelBuilderResult> children = new ArrayList<>();
 
-    DefaultModelBuilderResult(ProblemCollector<ModelProblem> problemCollector) {
+    DefaultModelBuilderResult(ModelBuilderRequest request, ProblemCollector<ModelProblem> problemCollector) {
+        this.request = request;
         this.problemCollector = problemCollector;
     }
 
+    @Override
+    public ModelBuilderRequest getRequest() {
+        return request;
+    }
+
     @Override
     public ModelSource getSource() {
         return source;
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java
index 3343c4678f..f3928494aa 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java
@@ -38,6 +38,7 @@
 import org.apache.maven.api.services.ProblemCollector;
 import org.apache.maven.api.services.model.ModelResolverException;
 import org.apache.maven.impl.InternalSession;
+import org.apache.maven.impl.RequestTraceHelper;
 import org.apache.maven.impl.model.ModelProblemUtils;
 import org.eclipse.aether.RepositoryEvent;
 import org.eclipse.aether.RepositoryEvent.EventType;
@@ -195,6 +196,7 @@ private Model loadPom(
                         pomArtifact.getGroupId() + ":" + pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion();
                 ModelBuilderRequest modelRequest = ModelBuilderRequest.builder()
                         .session(iSession)
+                        .trace(RequestTraceHelper.toMaven(request.getRequestContext(), trace))
                         .requestType(ModelBuilderRequest.RequestType.CONSUMER_DEPENDENCY)
                         .source(ModelSource.fromPath(pomArtifact.getPath(), gav))
                         // This merge is on purpose because otherwise user properties would override model
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/RequestTraceHelper.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/RequestTraceHelper.java
deleted file mode 100644
index 3ee54da7aa..0000000000
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/RequestTraceHelper.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.maven.impl.resolver;
-
-import java.util.stream.Collectors;
-
-import org.eclipse.aether.RequestTrace;
-import org.eclipse.aether.collection.CollectRequest;
-import org.eclipse.aether.collection.CollectStepData;
-import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
-import org.eclipse.aether.resolution.ArtifactRequest;
-import org.eclipse.aether.resolution.DependencyRequest;
-
-/**
- * Helper class to manage {@link RequestTrace} for better error logging.
- */
-public final class RequestTraceHelper {
-
-    /**
-     * Method that creates some informational string based on passed in {@link RequestTrace}. The contents of request
-     * trace can literally be anything, but this class tries to cover "most common" cases that are happening in Maven.
-     */
-    public static String interpretTrace(boolean detailed, RequestTrace requestTrace) {
-        while (requestTrace != null) {
-            Object data = requestTrace.getData();
-            if (data instanceof DependencyRequest request) {
-                return "dependency resolution for " + request;
-            } else if (data instanceof CollectRequest request) {
-                return "dependency collection for " + request;
-            } else if (data instanceof CollectStepData stepData) {
-                String msg = "dependency collection step for " + stepData.getContext();
-                if (detailed) {
-                    msg += ". Path to offending node from root:\n";
-                    msg += stepData.getPath().stream()
-                            .map(n -> " -> " + n.toString())
-                            .collect(Collectors.joining("\n"));
-                    msg += "\n => " + stepData.getNode();
-                }
-                return msg;
-            } else if (data instanceof ArtifactDescriptorRequest request) {
-                return "artifact descriptor request for " + request.getArtifact();
-            } else if (data instanceof ArtifactRequest request) {
-                return "artifact request for " + request.getArtifact();
-                // TODO: this class is not reachable here!
-                // } else if (data instanceof org.apache.maven.model.Plugin plugin) {
-                //    return "plugin " + plugin.getId();
-            }
-            requestTrace = requestTrace.getParent();
-        }
-
-        return "n/a";
-    }
-}
diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/RequestTraceHelperTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/RequestTraceHelperTest.java
new file mode 100644
index 0000000000..33294298ad
--- /dev/null
+++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/RequestTraceHelperTest.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.impl;
+
+import org.apache.maven.api.services.Request;
+import org.eclipse.aether.RequestTrace;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class RequestTraceHelperTest {
+
+    @Test
+    void testEnterWithRequestData() {
+        InternalSession session = mock(InternalSession.class);
+        Request<?> request = mock(Request.class);
+        org.apache.maven.api.services.RequestTrace existingTrace =
+                new org.apache.maven.api.services.RequestTrace(null, "test");
+
+        when(request.getTrace()).thenReturn(existingTrace);
+
+        RequestTraceHelper.ResolverTrace result = RequestTraceHelper.enter(session, request);
+
+        assertNotNull(result);
+        assertEquals(existingTrace, result.mvnTrace());
+        verify(session).setCurrentTrace(existingTrace);
+    }
+
+    @Test
+    void testInterpretTraceWithArtifactRequest() {
+        ArtifactRequest artifactRequest = mock(ArtifactRequest.class);
+        RequestTrace trace = RequestTrace.newChild(null, artifactRequest);
+
+        String result = RequestTraceHelper.interpretTrace(false, trace);
+
+        assertTrue(result.startsWith("artifact request for "));
+    }
+
+    @Test
+    void testToMavenWithNullTrace() {
+        assertNull(RequestTraceHelper.toMaven("test", null));
+    }
+
+    @Test
+    void testToResolverWithNullTrace() {
+        assertNull(RequestTraceHelper.toResolver(null));
+    }
+
+    @Test
+    void testExitResetsParentTrace() {
+        InternalSession session = mock(InternalSession.class);
+        org.apache.maven.api.services.RequestTrace parentTrace =
+                new org.apache.maven.api.services.RequestTrace(null, "parent");
+        org.apache.maven.api.services.RequestTrace currentTrace =
+                new org.apache.maven.api.services.RequestTrace(parentTrace, "current");
+
+        RequestTraceHelper.ResolverTrace resolverTrace =
+                new RequestTraceHelper.ResolverTrace(session, "test", null, currentTrace);
+
+        RequestTraceHelper.exit(resolverTrace);
+
+        verify(session).setCurrentTrace(parentTrace);
+    }
+}
diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelBuilderResultTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelBuilderResultTest.java
new file mode 100644
index 0000000000..beea6fa88b
--- /dev/null
+++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelBuilderResultTest.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.impl.model;
+
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.services.BuilderProblem;
+import org.apache.maven.api.services.ModelBuilderRequest;
+import org.apache.maven.api.services.ModelProblem;
+import org.apache.maven.api.services.ModelSource;
+import org.apache.maven.api.services.ProblemCollector;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+
+class DefaultModelBuilderResultTest {
+
+    private ModelBuilderRequest request;
+    private ProblemCollector<ModelProblem> problemCollector;
+    private DefaultModelBuilderResult result;
+    private ModelSource source;
+    private Model fileModel;
+    private Model rawModel;
+    private Model effectiveModel;
+
+    @BeforeEach
+    void setUp() {
+        request = mock(ModelBuilderRequest.class);
+        problemCollector = ProblemCollector.create(10);
+        result = new DefaultModelBuilderResult(request, problemCollector);
+
+        source = mock(ModelSource.class);
+        fileModel = mock(Model.class);
+        rawModel = mock(Model.class);
+        effectiveModel = mock(Model.class);
+    }
+
+    @Test
+    void testModelLifecycle() {
+        // Test initial state
+        assertNull(result.getSource());
+        assertNull(result.getFileModel());
+        assertNull(result.getRawModel());
+        assertNull(result.getEffectiveModel());
+        assertEquals(0L, result.getProblemCollector().problems().count());
+
+        // Set and verify source
+        result.setSource(source);
+        assertSame(source, result.getSource());
+
+        // Set and verify file model
+        result.setFileModel(fileModel);
+        assertSame(fileModel, result.getFileModel());
+
+        // Set and verify raw model
+        result.setRawModel(rawModel);
+        assertSame(rawModel, result.getRawModel());
+
+        // Set and verify effective model
+        result.setEffectiveModel(effectiveModel);
+        assertSame(effectiveModel, result.getEffectiveModel());
+    }
+
+    @Test
+    void testProblemCollection() {
+        ModelProblem problem = mock(ModelProblem.class);
+        Mockito.when(problem.getSeverity()).thenReturn(BuilderProblem.Severity.ERROR);
+        problemCollector.reportProblem(problem);
+
+        assertEquals(1, result.getProblemCollector().problems().count());
+        assertSame(problem, result.getProblemCollector().problems().findFirst().get());
+    }
+
+    @Test
+    void testChildrenManagement() {
+        DefaultModelBuilderResult child1 = new DefaultModelBuilderResult(request, problemCollector);
+        DefaultModelBuilderResult child2 = new DefaultModelBuilderResult(request, problemCollector);
+
+        result.getChildren().add(child1);
+        result.getChildren().add(child2);
+
+        assertEquals(2, result.getChildren().size());
+        assertTrue(result.getChildren().contains(child1));
+        assertTrue(result.getChildren().contains(child2));
+    }
+
+    @Test
+    void testRequestAssociation() {
+        assertSame(request, result.getRequest());
+    }
+}
diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/standalone/RequestTraceTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/standalone/RequestTraceTest.java
new file mode 100644
index 0000000000..b9eaf6b4d0
--- /dev/null
+++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/standalone/RequestTraceTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.impl.standalone;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.maven.api.ArtifactCoordinates;
+import org.apache.maven.api.DownloadedArtifact;
+import org.apache.maven.api.Node;
+import org.apache.maven.api.PathScope;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.services.DependencyResolver;
+import org.apache.maven.api.services.DependencyResolverRequest;
+import org.apache.maven.api.services.ModelBuilder;
+import org.apache.maven.api.services.ModelBuilderRequest;
+import org.apache.maven.api.services.ModelBuilderResult;
+import org.apache.maven.api.services.ModelSource;
+import org.apache.maven.api.services.RequestTrace;
+import org.apache.maven.impl.InternalSession;
+import org.apache.maven.impl.RequestTraceHelper;
+import org.eclipse.aether.AbstractRepositoryListener;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositoryEvent;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class RequestTraceTest {
+
+    @Test
+    void testTraces() {
+        Session session = ApiRunner.createSession();
+
+        ModelBuilder builder = session.getService(ModelBuilder.class);
+        ModelBuilderResult result = builder.newSession()
+                .build(ModelBuilderRequest.builder()
+                        .session(session)
+                        .source(ModelSource.fromPath(Paths.get("pom.xml").toAbsolutePath()))
+                        .requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT)
+                        .recursive(true)
+                        .build());
+        assertNotNull(result.getEffectiveModel());
+
+        List<RepositoryEvent> events = new CopyOnWriteArrayList<>();
+        ((DefaultRepositorySystemSession) InternalSession.from(session).getSession())
+                .setRepositoryListener(new AbstractRepositoryListener() {
+                    @Override
+                    public void artifactResolved(RepositoryEvent event) {
+                        events.add(event);
+                    }
+                });
+
+        ArtifactCoordinates coords =
+                session.createArtifactCoordinates("org.apache.maven:maven-api-core:4.0.0-alpha-13");
+        DownloadedArtifact res = session.resolveArtifact(coords);
+        assertNotNull(res);
+        assertNotNull(res.getPath());
+        assertTrue(Files.exists(res.getPath()));
+
+        Node node = session.getService(DependencyResolver.class)
+                .collect(DependencyResolverRequest.builder()
+                        .trace(new RequestTrace("collect", null, null))
+                        .session(session)
+                        .requestType(DependencyResolverRequest.RequestType.COLLECT)
+                        .dependency(session.createDependencyCoordinates(coords))
+                        .pathScope(PathScope.MAIN_RUNTIME)
+                        .build())
+                .getRoot()
+                .getChildren()
+                .iterator()
+                .next();
+
+        for (RepositoryEvent event : events) {
+            org.eclipse.aether.RequestTrace trace = event.getTrace();
+            assertNotNull(trace);
+
+            RequestTrace rTrace = RequestTraceHelper.toMaven("collect", trace);
+            assertNotNull(rTrace);
+            assertNotNull(rTrace.parent());
+        }
+
+        assertNotNull(node);
+        assertEquals(6, node.getChildren().size());
+    }
+}