Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Bug: Tracing throws a reflection exception when handling aggregate exception #769

Open
AdithyaAthreya opened this issue Feb 19, 2025 · 2 comments
Assignees
Labels
area/tracing Core tracing utility bug Unexpected, reproducible and unintended software behaviour

Comments

@AdithyaAthreya
Copy link

AdithyaAthreya commented Feb 19, 2025

Expected Behaviour

Aggregate exceptions are handled correctly by the power tools tracing library.

Current Behaviour

I am currently working with a .NET 8 AWS lambda which is asynchronous and invoked from AWS api gateway. From the async function handler itself, I call another async method which throws an exception. When tracing is handling this aggregate exception, I get a reflection related exception in my logs. A screenshot of the output response of the lambda has been attached.

Image

I did read this post: #223. But this doesn't seem to fix the current exception I'm getting.

Code snippet

namespace TestCode
{
	public class Function
	{
		[Tracing(CaptureMode = TracingCaptureMode.EnvironmentVariable))]
		[Logging(ClearState = true, LogEvent = true, LoggerOutputCase = LoggerOutputCase.CamelCase)]
		public async Task<string> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
		{
			try
			{
				await TestExceptionMethod();
			}
			catch (AggregateException ex)
			{
				if(ex.InnerException is NotImplementedException)
				{
					throw new Exception("NotImplementedException block of aggregate exception");
				}

				throw new Exception("Exception block of aggregate exception");
			}			
			catch (Exception ex)
			{
				var extraKeys = TransformToAcceptableFormat(ex.Data);
				Logger.LogError(extraKeys: extraKeys, exception: ex,
					message: "Exception in ServiceMenu-Delta retrieval");
				var errorBody = GenerateErrorObject(errorCode: HttpStatusCode.InternalServerError, 
					ErrorTitles.INTERNAL_SERVER_ERROR_TITLE,
					[ex.Message]);
				throw new InternalServerErrorException(errorBody);
			}
		}

		[Tracing(CaptureMode = TracingCaptureMode.Error)]
		private async Task TestExceptionMethod()
		{
			await Task.Delay(10);
			throw new Exception("from test exception method");
		}
	}
}

Possible Solution

No response

Steps to Reproduce

Add the above code snippet in a lambda project and upload to AWS
Setup a simple AWS api gateway GET endpoint and invoke it from postman
Observe the response returned by the api call in postman
Observe the cloudwatch logs and traces

Powertools for AWS Lambda (.NET) version

1.6.0

AWS Lambda function runtime

dotnet8

Debugging logs

@AdithyaAthreya AdithyaAthreya added bug Unexpected, reproducible and unintended software behaviour triage Pending triage from maintainers labels Feb 19, 2025
Copy link

boring-cyborg bot commented Feb 19, 2025

Thanks for opening your first issue here! We'll come back to you as soon as we can.
In the meantime, check out the #dotnet channel on our Powertools for AWS Lambda Discord: Invite link

@hjgraca hjgraca added the area/tracing Core tracing utility label Feb 20, 2025
@hjgraca hjgraca self-assigned this Feb 20, 2025
@hjgraca hjgraca moved this to 📋 Backlog in Powertools for AWS Lambda (.NET) Feb 20, 2025
@hjgraca
Copy link
Contributor

hjgraca commented Feb 24, 2025

Hi @AdithyaAthreya, thank you for opening the issue, after some careful consideration we don't believe this is an issue and our reasoning is that the error and stack trace you are seeing looks correct.

The stack trace accurately reflects the code's execution path, which necessarily includes the Tracing. We recommend accepting this as expected behaviour unless stack trace purity is an absolute requirement.

The stack trace will always include the AOP (Tracing) because:

  • The exception physically occurs within the aspect's Around method
  • .NET's stack trace mechanism accurately reports the actual execution path
  • Any attempt to modify the stack trace would require unsafe reflection or runtime modifications

Example stack trace

at TestCode.Function.TestExceptionMethod()
at AWS.Lambda.Powertools.Tracing.Internal.TracingAspect.Around()
at TestCode.Function.TestExceptionMethod()
at TestCode.Function.FunctionHandler()

Some issues in your example

  • When using async/await, AggregateException is automatically unwrapped. There's no need to catch it explicitly.
  • Creating a new InternalServerErrorException loses the original stack trace and context.
  • The exception handling is creating multiple layers of wrapping, making debugging harder.
catch (AggregateException ex)
{
    if(ex.InnerException is NotImplementedException)
    {
        throw new Exception("NotImplementedException block of aggregate exception");
    }

    throw new Exception("Exception block of aggregate exception");
}			
catch (Exception ex)
{
    var extraKeys = TransformToAcceptableFormat(ex.Data);
    Logger.LogError(extraKeys: extraKeys, exception: ex,
        message: "Exception in ServiceMenu-Delta retrieval");
    var errorBody = GenerateErrorObject(errorCode: HttpStatusCode.InternalServerError, 
        ErrorTitles.INTERNAL_SERVER_ERROR_TITLE,
        [ex.Message]);
    throw new InternalServerErrorException(errorBody); // This is wrong
}

Updated example

public async Task<string> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
{
    try
    {
        await TestExceptionMethod();
        return "Success";
    }
    catch (Exception ex)
    {
        var extraKeys = TransformToAcceptableFormat(ex.Data);
        Logger.LogError(extraKeys: extraKeys, exception: ex,
            message: "Exception in ServiceMenu-Delta retrieval");
            
        // Either rethrow the original exception
        throw;
        
        // Or if you must return an API error, wrap the original exception
        // throw new InternalServerErrorException(errorBody, ex);
    }
}
  1. Use a single catch block for Exception
  2. Either rethrow with throw to preserve stack trace
  3. If wrapping is required, pass the original exception as inner exception

Let me know if you have any questions.
Again thank you for opening the issue.

@dreamorosi dreamorosi removed the triage Pending triage from maintainers label Feb 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/tracing Core tracing utility bug Unexpected, reproducible and unintended software behaviour
Projects
Status: 📋 Backlog
Development

No branches or pull requests

3 participants