diff --git a/pkg/services/common/ape/checker.go b/pkg/services/common/ape/checker.go
index c9b0b7363..0f342df46 100644
--- a/pkg/services/common/ape/checker.go
+++ b/pkg/services/common/ape/checker.go
@@ -104,7 +104,7 @@ func (c *checkerCoreImpl) CheckAPE(ctx context.Context, prm CheckPrm) error {
 	if found && status == apechain.Allow {
 		return nil
 	}
-	return newChainRouterError(prm.Request.Operation(), status)
+	return newChainRouterError(rt, prm.Request, status)
 }
 
 // isValidBearer checks whether bearer token was correctly signed by authorized
diff --git a/pkg/services/common/ape/error.go b/pkg/services/common/ape/error.go
index d3c381de7..c881fc076 100644
--- a/pkg/services/common/ape/error.go
+++ b/pkg/services/common/ape/error.go
@@ -3,31 +3,131 @@ package ape
 import (
 	"fmt"
 
+	aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request"
 	apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
+	policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
+	"go.uber.org/zap/zapcore"
 )
 
 // ChainRouterError is returned when chain router validation prevents
 // the APE request from being processed (no rule found, access denied, etc.).
 type ChainRouterError struct {
-	operation string
-	status    apechain.Status
+	target  policyengine.RequestTarget
+	request aperequest.Request
+	status  apechain.Status
 }
 
 func (e *ChainRouterError) Error() string {
-	return fmt.Sprintf("access to operation %s is denied by access policy engine: %s", e.Operation(), e.Status())
+	return fmt.Sprintf("access to operation %s is denied by access policy engine: %s", e.request.Operation(), e.status)
 }
 
-func (e *ChainRouterError) Operation() string {
-	return e.operation
-}
-
-func (e *ChainRouterError) Status() apechain.Status {
-	return e.status
-}
-
-func newChainRouterError(operation string, status apechain.Status) *ChainRouterError {
+func newChainRouterError(target policyengine.RequestTarget, request aperequest.Request, status apechain.Status) *ChainRouterError {
 	return &ChainRouterError{
-		operation: operation,
-		status:    status,
+		target:  target,
+		request: request,
+		status:  status,
 	}
 }
+
+func (e *ChainRouterError) MarshalLogObject(enc zapcore.ObjectEncoder) error {
+	enc.AddString("status", e.status.String())
+
+	if err := enc.AddObject("request", zapcore.ObjectMarshalerFunc(
+		func(innerEnc zapcore.ObjectEncoder) error {
+			return e.marshalRequest(innerEnc)
+		})); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (e *ChainRouterError) marshalTarget(enc zapcore.ObjectEncoder) error {
+	target := e.target
+
+	hasNamespace := target.Namespace != nil
+	hasContainer := target.Container != nil
+	hasUser := target.User != nil
+	hasGroups := len(target.Groups) > 0
+
+	if !hasNamespace && !hasContainer && !hasUser && !hasGroups {
+		enc.AddString("type", "empty")
+		return nil
+	}
+
+	if hasNamespace {
+		enc.AddString("namespace", target.Namespace.Name)
+	}
+
+	if hasContainer {
+		enc.AddString("container", target.Container.Name)
+	}
+
+	if hasUser {
+		enc.AddString("user", target.User.Name)
+	}
+
+	if hasGroups {
+		if err := enc.AddArray("groups", zapcore.ArrayMarshalerFunc(
+			func(arrayEnc zapcore.ArrayEncoder) error {
+				for i := range target.Groups {
+					arrayEnc.AppendString(target.Groups[i].Name)
+				}
+				return nil
+			})); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (e *ChainRouterError) marshalRequest(enc zapcore.ObjectEncoder) error {
+	enc.AddString("operation", e.request.Operation())
+
+	if err := enc.AddObject("target", zapcore.ObjectMarshalerFunc(
+		func(innerEnc zapcore.ObjectEncoder) error {
+			return e.marshalTarget(innerEnc)
+		})); err != nil {
+		return err
+	}
+
+	if err := enc.AddObject("properties", zapcore.ObjectMarshalerFunc(
+		func(innerEnc zapcore.ObjectEncoder) error {
+			for key, value := range e.request.Properties() {
+				innerEnc.AddString(key, value)
+			}
+			return nil
+		})); err != nil {
+		return err
+	}
+
+	if err := enc.AddObject("resource", zapcore.ObjectMarshalerFunc(
+		func(innerEnc zapcore.ObjectEncoder) error {
+			return e.marshalResource(innerEnc)
+		})); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (e *ChainRouterError) marshalResource(enc zapcore.ObjectEncoder) error {
+	resource, ok := e.request.Resource().(aperequest.Resource)
+	if !ok {
+		return nil
+	}
+
+	enc.AddString("name", resource.Name())
+	if err := enc.AddObject("properties", zapcore.ObjectMarshalerFunc(
+		func(innerEnc zapcore.ObjectEncoder) error {
+			for key, value := range resource.Properties() {
+				innerEnc.AddString(key, value)
+			}
+			return nil
+		})); err != nil {
+		return err
+	}
+
+	return nil
+}