MalformedContinuationTokenException should be made public
See original GitHub issueDescribe the bug
We include CosmosDB continuation token in the nextLink
that we return to our API caller during pagination. Sometimes, caller accidentally clip or alter the continuation token when calling us to retrieve the next page. In that case, SDK would throw CosmosException
with inner exception MalformedContinuationTokenException
. We would like to catch that so we can tell user what’s wrong specifically. However, the latter is an internal class which prevents us from doing so. The only workaround is to parse the CosmosException
message which is fragile. Can MalformedContinuationTokenException
be made public?
To Reproduce
try
{
var iterator = container.GetItemQueryIterator<Foo>(query, continuationToken.Substring(0, continuationToken.Length-1), queryOptions);
var response = await iterator.ReadNextAsync(ct);
}
catch (CosmosException ex) // when (ex.InnerException is `MalformedContinuationTokenException`)
{
// ...
}
Expected behavior
MalformedContinuationTokenException
type is public and can be compared against. Its constructor can remain internal.
Actual behavior The type is internal, so we can’t check against the type.
Environment summary SDK Version: 3.25 OS Version: Windows 11
Additional context Add any other context about the problem here (for example, complete stack traces or logs).
Microsoft.Azure.Cosmos.CosmosException : Response status code does not indicate success: BadRequest (400); Substatus: 0; ActivityId: ; Reason: (Response status code does not indicate success: BadRequest (400); Substatus: 0; ActivityId: ; Reason: (Malformed Continuation Token: [{"token":"+RID:~oN4fAM-fK9UGAAAAAAAAAA==#RT:3#TRC:6#ISV:2#IEO:65567#QCF:4#FPC:AQYAAAAAAAAACgAAAAAAAAA=","range":{"min":"","max":"FF"}}););
---> Microsoft.Azure.Cosmos.Query.Core.Exceptions.MalformedContinuationTokenException: Malformed Continuation Token: [{"token":"+RID:~oN4fAM-fK9UGAAAAAAAAAA==#RT:3#TRC:6#ISV:2#IEO:65567#QCF:4#FPC:AQYAAAAAAAAACgAAAAAAAAA=","range":{"min":"","max":"FF"}}
---> Microsoft.Azure.Cosmos.Query.Core.Monads.ExceptionWithStackTraceException: TryCatch resulted in an exception. ---> Microsoft.Azure.Cosmos.Json.JsonMissingEndArrayException: Missing an end array ("]") symbol in JSON., Windows/10.0.22572 cosmos-netstandard-sdk/3.24.1
at Microsoft.Azure.Cosmos.Json.JsonReader.JsonTextReader.Read()
at Microsoft.Azure.Cosmos.Json.JsonNavigator.JsonTextNavigator.Parser.ParseObjectNode(IJsonTextReaderPrivateImplementation jsonTextReader)
at Microsoft.Azure.Cosmos.Json.JsonNavigator.JsonTextNavigator.Parser.ParseNode(IJsonTextReaderPrivateImplementation jsonTextReader)
at Microsoft.Azure.Cosmos.Json.JsonNavigator.JsonTextNavigator.Parser.ParseArrayNode(IJsonTextReaderPrivateImplementation jsonTextReader)
at Microsoft.Azure.Cosmos.Json.JsonNavigator.JsonTextNavigator.Parser.ParseNode(IJsonTextReaderPrivateImplementation jsonTextReader)
at Microsoft.Azure.Cosmos.Json.JsonNavigator.JsonTextNavigator.Parser.Parse(IJsonTextReaderPrivateImplementation jsonTextReader)
at Microsoft.Azure.Cosmos.Json.JsonNavigator.JsonTextNavigator.<>c__DisplayClass3_0.<.ctor>g__CreateRootNode|0()
at Microsoft.Azure.Cosmos.Json.JsonNavigator.JsonTextNavigator..ctor(ReadOnlyMemory`1 buffer)
at Microsoft.Azure.Cosmos.Json.JsonNavigator.Create(ReadOnlyMemory`1 buffer)
at Microsoft.Azure.Cosmos.CosmosElements.CosmosElement.Monadic.CreateFromBuffer[TCosmosElement](ReadOnlyMemory`1 buffer)
--- End of inner exception stack trace ---
at Microsoft.Azure.Cosmos.CosmosElements.CosmosElement.Monadic.CreateFromBuffer[TCosmosElement](ReadOnlyMemory`1 buffer)
at Microsoft.Azure.Cosmos.CosmosElements.CosmosElement.Monadic.Parse[TCosmosElement](String serializedCosmosElement)
at Microsoft.Azure.Cosmos.CosmosElements.CosmosElement.Monadic.Parse(String serializedCosmosElement)
at Microsoft.Azure.Cosmos.Query.QueryIterator.Create(ContainerCore containerCore, CosmosQueryClient client, CosmosClientContext clientContext, SqlQuerySpec sqlQuerySpec, String continuationToken, FeedRangeInternal feedRangeInternal, QueryRequestOptions queryRequestOptions, String resourceLink, Boolean isContinuationExpected, Boolean allowNonValueAggregateQuery, Boolean forcePassthrough, PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
at Microsoft.Azure.Cosmos.ContainerCore.GetItemQueryStreamIteratorInternal(SqlQuerySpec sqlQuerySpec, Boolean isContinuationExcpected, String continuationToken, FeedRangeInternal feedRange, QueryRequestOptions requestOptions)
at Microsoft.Azure.Cosmos.ContainerCore.GetItemQueryStreamIterator(QueryDefinition queryDefinition, String continuationToken, QueryRequestOptions requestOptions)
at Microsoft.Azure.Cosmos.ContainerInlineCore.GetItemQueryStreamIterator(QueryDefinition queryDefinition, String continuationToken, QueryRequestOptions requestOptions)
at Microsoft.Azure.Cosmos.ContainerCore.GetItemQueryIterator[T](QueryDefinition queryDefinition, String continuationToken, QueryRequestOptions requestOptions)
at Microsoft.Azure.Cosmos.ContainerInlineCore.GetItemQueryIterator[T](QueryDefinition queryDefinition, String continuationToken, QueryRequestOptions requestOptions)
Issue Analytics
- State:
- Created 2 years ago
- Comments:10 (9 by maintainers)
Top GitHub Comments
Not intentionally we presume - I think they URLDecoded our
nextLink
and did a split string on=
. CosmosDB token often has==
in them.We indeed would like to return 400 to them. However, when Cosmos DB returns 400 to us, it can theoretically be a bug in our code (e.g., invalid query), or in our user’s code (malformed token in this case). Thus, we can’t just blindly propagate Cosmos DB’s 400 as our service’s 400. We can parse the
CosmosException
message, but we doubt the message is guaranteed to remain the same forever. During debugging, we notice the underlying exact reason is already in its inner exception, but unfortunately the type is not public.@xiejiams Please see above comment as well.