Skip to content

Add error handling for deserialization in dynamo db #3937

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

Open
wants to merge 3 commits into
base: development
Choose a base branch
from

Conversation

GarrettBeatty
Copy link
Contributor

@GarrettBeatty GarrettBeatty commented Jul 28, 2025

Description

Update logic for error messaging in DynamoDB when the user does not provide DynamicDependency for nested properties when running in native AOT mode.

Previously if a user provided something like https://github.com/aws/aws-sdk-net/blob/gcbeatty/dynamotesting/DynamoDBGenericTypeTest/Program.cs#L18 , where they didnt have dynamicdependency for the List<CarQuoteExcess> we would throw an error like

System.InvalidOperationException: Unable to convert DynamoDB entry [Amazon.DynamoDBv2.DocumentModel.DynamoDBList] of type Amazon.DynamoDBv2.DocumentModel.DynamoDBList to property Excesses of type System.Collections.Generic.List`1[[IQ.Car.Quote.CarQuoteExcess, IQ.Car.Quote, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]

which doesnt really help the user. (The error comes from

"Unable to convert DynamoDB entry [{0}] of type {1} to property {2} of type {3}",
).

This change updates it so that we check that all nested properties can also be instantiated.

Motivation and Context

#3871

Testing

Ran sample project i made.

I tested by doing different combinations of commenting out

 [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(DynamoDBGenericTypeTest.CarQuoteResponse))]
 [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(List<DynamoDBGenericTypeTest.CarQuoteExcess>))]
 [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(DynamoDBGenericTypeTest.CarQuoteExcess))]

In below test output, i commented out

 [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(List<DynamoDBGenericTypeTest.CarQuoteExcess>))]

https://github.com/aws/aws-sdk-net/blob/gcbeatty/dynamotesting/DynamoDBGenericTypeTest/Program.cs

PS C:\dev\repos\aws-sdk-net-staging\DynamoDBGenericTypeTest> dotnet publish -r win-x64 -c Release
Restore complete (2.2s)
You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy
  AWSSDK.Core.NetStandard net8.0 succeeded (3.0s) → C:\dev\repos\aws-sdk-net-staging\sdk\src\Core\bin\Release\net8.0\AWSSDK.Core.dll       
  AWSSDK.DynamoDBv2.NetStandard net8.0 succeeded (3.3s) → C:\dev\repos\aws-sdk-net-staging\sdk\src\Services\DynamoDBv2\bin\Release\net8.0\AWSSDK.DynamoDBv2.dll
  DynamoDBGenericTypeTest succeeded with 1 warning(s) (22.6s) → bin\Release\net8.0\win-x64\publish\
    C:\dev\repos\aws-sdk-net-staging\DynamoDBGenericTypeTest\Program.cs(86,27): warning CS0618: 'DynamoDBContext.DynamoDBContext(IAmazonDynamoDB)' is obsolete: 'Use the DynamoDBContextBuilder to construct a DynamoDBContext with the recommended configuration.'

Build succeeded with 1 warning(s) in 32.4s
DynamoDB Generic Collection Test
==============================
Checking/creating test table...
Table QuoteResponse already exists
Saving test quote with ID: test-5882643f
Type System.Collections.Generic.List`1[DynamoDBGenericTypeTest.CarQuoteExcess] is unsupported, it cannot be instantiated. Since the application is running in Native AOT mode the type could possibly be trimmed. This can happen if the type being created is a nested type of a type being used for saving and loading DynamoDB items. This can be worked around by adding the "[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.List`1[DynamoDBGenericTypeTest.CarQuoteExcess]))]" attribute to the constructor of the parent type. If the parent type can not be modified the attribute can also be used on the method invoking the DynamoDB sdk or some other method that you are sure is not being trimmed.
   at Amazon.DynamoDBv2.DataModel.StorageConfig..ctor(Type) + 0x311
   at Amazon.DynamoDBv2.DataModel.ItemStorageConfig..ctor(Type) + 0x27
   at Amazon.DynamoDBv2.DataModel.ItemStorageConfigCache.CreateStorageConfig(Type, String, DynamoDBFlatConfig) + 0x41
   at Amazon.DynamoDBv2.DataModel.ItemStorageConfigCache.GetConfig(Type, DynamoDBFlatConfig, Boolean) + 0x175
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.ObjectToItemStorage(Object, Type, Boolean, DynamoDBFlatConfig) + 0x33
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.<SaveHelperAsync>d__48.MoveNext() + 0x5d
--- End of stack trace from previous location ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb2
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4b
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.<SaveHelperAsync>d__47`1.MoveNext() + 0xef
--- End of stack trace from previous location ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb2
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4b
   at Amazon.DynamoDBv2.DataModel.DynamoDBContext.<SaveAsync>d__131`1.MoveNext() + 0x148
--- End of stack trace from previous location ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb2
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4b
   at DynamoDBGenericTypeTest.Program.<Main>d__0.MoveNext() + 0x4bc

Test complete. Press any key to exit.

Dry-run 1f12b0c9-7516-4036-8fef-fb967bed2a41 in progress

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My code follows the code style of this project
  • My change requires a change to the documentation
  • I have updated the documentation accordingly
  • I have read the README document
  • I have added tests to cover my changes
  • All new and existing tests passed

License

  • I confirm that this pull request can be released under the Apache 2 license

Copy link
Member

@normj normj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the FromDynamoDBEntry will be called recursively for each property which will trigger the instantiation check do we really need to do a deep inspection. Seems like we will check from the root object if everything in the object hierarchy can be instantiated and then check again at each level down the hierarcy.

@GarrettBeatty
Copy link
Contributor Author

Since the FromDynamoDBEntry will be called recursively for each property which will trigger the instantiation check do we really need to do a deep inspection. Seems like we will check from the root object if everything in the object hierarchy can be instantiated and then check again at each level down the hierarcy.

let me double check to see if this is the case

@GarrettBeatty
Copy link
Contributor Author

Since the FromDynamoDBEntry will be called recursively for each property which will trigger the instantiation check do we really need to do a deep inspection. Seems like we will check from the root object if everything in the object hierarchy can be instantiated and then check again at each level down the hierarcy.

this made me take another look at the code and i realized the way i was going about it wrong (although im not sure why it worked?)

The latest code now checks during deserialization. and similar to the serialization process, when it cannot instantiate something, it throws an error. i re-ran my test program and it seems to work

Checking/creating test table...
Table QuoteResponse already exists
Saving test quote with ID: test-7bf322d2
Save successful
Querying for Id: test-7bf322d2
Type System.Collections.Generic.List`1[[DynamoDBGenericTypeTest.CarQuoteExcess, DynamoDBGenericTypeTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] is unsupported, it cannot be instantiated. Since the application is running in Native AOT mode the type could possibly be trimmed. This can happen if the type being created is a nested type of a type being used for saving and loading DynamoDB items. This can be worked around by adding the "[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(System.Collections.Generic.List`1[[DynamoDBGenericTypeTest.CarQuoteExcess, DynamoDBGenericTypeTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]))]" attribute to the constructor of the parent type. If the parent type can not be modified the attribute can also be used on the method invoking the DynamoDB sdk or some other method that you are sure is not being trimmed.

@GarrettBeatty GarrettBeatty marked this pull request as ready for review July 30, 2025 01:29
@GarrettBeatty GarrettBeatty requested a review from normj July 30, 2025 01:29
@GarrettBeatty GarrettBeatty requested a review from Copilot July 30, 2025 01:37
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR improves error handling for DynamoDB when users don't provide proper DynamicDependency attributes for nested objects in Native AOT mode. It replaces silent failures with clear, actionable error messages that guide users on how to fix trimming issues.

  • Replaces silent failures with explicit error messages when types cannot be instantiated
  • Provides AOT-specific guidance including exact DynamicDependency attribute syntax
  • Adds helpful context about where to place the attributes (constructor, method, etc.)

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
sdk/src/Services/DynamoDBv2/Custom/DataModel/ContextInternal.cs Converts silent failures to informative exceptions with AOT-specific error messages in three type instantiation methods
generator/.DevConfigs/abdc3b34-805a-44fc-996e-8fa58e021235.json Adds changelog entry for the DynamoDBv2 error handling improvement

@GarrettBeatty GarrettBeatty changed the title Add error handling for nested objects in dynamo db for native aot. Add error handling for deserialization in dynamo db Jul 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants