Skip to content

Return 200 empty payload for cached reads with empty result - #3822

Open
Souvik Ghosh (souvikghosh04) wants to merge 1 commit into
mainfrom
bugfix/3704-cached-empty-result-500
Open

Souvik Ghosh (souvikghosh04) wants to merge 1 commit into
mainfrom
bugfix/3704-cached-empty-result-500

Conversation

@souvikghosh04

Copy link
Copy Markdown
Contributor

Summary

Fixes #3704 (and its duplicate #3446).

When entity/runtime caching is enabled and a REST/GraphQL read returns zero
rows
, DAB returned HTTP 500 (System.InvalidOperationException) during
response serialization. With caching disabled, the identical request correctly
returns 200 with an empty payload (e.g. {"value":[]}).

Root cause

In the cache read path,
SqlQueryEngine.GetResultInCacheScenarioParseResultIntoJsonDocument(JsonElement? result):

  • For an empty result set, the executor's GetJsonResultAsync<JsonElement> yields
    default(JsonElement) — a struct whose ValueKind is JsonValueKind.Undefined
    and which has no backing JsonDocument. Because it is a value type, it is not
    null, so the nullable result has a value.
  • ParseResultIntoJsonDocument then called
    JsonSerializer.SerializeToUtf8Bytes(result), which invokes
    JsonElement.WriteToCheckValidInstance() and throws
    InvalidOperationException, surfaced as HTTP 500.

The non-cached path never hits this: it returns a null JsonDocument? for an
empty result, which downstream renders as an empty payload. The cache path was
missing that empty guard. The failure occurs on both cache miss and cache hit,
and applies to list (FOR JSON PATH) and by-PK reads, for both REST and
GraphQL
(this method is shared).

Fix

Guard the Undefined case in ParseResultIntoJsonDocument and return null,
matching the non-cached empty-result path:

if (result is { ValueKind: JsonValueKind.Undefined })
{
    return null;
}

The pre-existing null-nullable behavior (serializing to a JSON null document)
is intentionally left unchanged, since only the Undefined element throws.

Tests

  • Added SqlQueryEngineHelperTests.ParseResultIntoJsonDocument_UndefinedElement_ReturnsNull,
    which invokes the method with default(JsonElement) and asserts it returns
    null (previously it threw InvalidOperationException).
  • The existing ParseResultIntoJsonDocument_HandlesValuesAndNull cases continue
    to pass unchanged.
  • All 8 SqlQueryEngineHelperTests pass; dotnet format --verify-no-changes is
    clean on the changed files.

When entity/runtime caching is enabled and a read returns zero rows, the cached
value surfaces as a default(JsonElement) with JsonValueKind.Undefined and no
backing document. ParseResultIntoJsonDocument called
JsonSerializer.SerializeToUtf8Bytes on it, which throws InvalidOperationException
via JsonElement.WriteTo -> CheckValidInstance(), producing HTTP 500.

Guard the Undefined case and return null, matching the non-cached path that
renders an empty payload. This path is shared by REST and GraphQL. Adds a
regression unit test.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The fix matches existing non-cached empty-result behavior and has focused regression coverage.

Review effort: Lite
Findings: None

What changed in this PR

Fixes cached empty SQL reads that previously caused HTTP 500 by handling undefined JsonElement values before serialization.

Changes:

  • Return null for undefined cached results.
  • Add a regression unit test.
File Description
src/​Core/​Resolvers/​SqlQueryEngine.cs Guards undefined cached results.
src/​Service.Tests/​UnitTests/​SqlQueryEngineHelperTests.cs Tests undefined-element handling.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Review In Progress

Development

Successfully merging this pull request may close these issues.

[Bug]: 500 InvalidOperationException on cached REST read when result is empty

5 participants