Skip to content

Return null from GetConnectorType on empty/missing schema payload#3050

Open
EricBuist wants to merge 1 commit intomicrosoft:mainfrom
EricBuist:users/ericbuist/fix-error-on-empty-schema-field
Open

Return null from GetConnectorType on empty/missing schema payload#3050
EricBuist wants to merge 1 commit intomicrosoft:mainfrom
EricBuist:users/ericbuist/fix-error-on-empty-schema-field

Conversation

@EricBuist
Copy link
Copy Markdown
Contributor

When a connector's x-ms-dynamic-schema or x-ms-dynamic-properties sub-call returns a 200 OK response whose body is empty or whose valuePath doesn't resolve, ExtractFromJson yields default(JsonElement) (ValueKind == Undefined). GetConnectorType then forwarded that default value to GetConnectorTypeInternal, which called je.ToString() (producing "") and passed it to OpenApiStringReader.ReadFragment. Deep inside Microsoft.OpenApi.Readers.OpenApiTextReaderReader.LoadYamlDocument, YamlStream.Documents.First() was invoked on an empty document stream and threw InvalidOperationException("Sequence contains no elements"). The exception surfaced out of GetConnectorReturnTypeAsync / GetConnectorTypeAsync as an opaque LINQ failure with no hint that the real cause was a dynamic-schema payload that didn't contain the expected property.

Real-world repro: Azure DevOps GetQueryResultsV2 declares its items as x-ms-dynamic-properties with operationId=GetQueryResultWorkItemSchema and itemValuePath=Fields. For some valid query shapes (e.g. queries whose saved columnOptions don't map to populated Fields), the sub-call returns 200 OK with a body that has no usable value at Fields. The static 5-layer recursion through GetConnectorTypeInternalAsync then hit LoadYamlDocument and failed with "Sequence contains no elements" instead of simply falling back to the static return type.

Fix

File: src/libraries/Microsoft.PowerFx.Connectors/ConnectorFunction.cs

GetConnectorType now checks JsonElement.ValueKind against Undefined / Null before delegating to GetConnectorTypeInternal and returns null when the extracted element is not usable. The two async callers (GetConnectorSuggestionsFromDynamicSchemaAsync and GetConnectorSuggestionsFromDynamicPropertyAsync) recognize the new null return, log a warning identifying the offending valuePath / itemValuePath, and return null themselves. The rest of the recursion already treats null as "no dynamic extension resolved" (see GetConnectorTypeInternalAsync line 683), so null propagates cleanly all the way back to GetConnectorReturnTypeAsync callers that can then fall back to the static ReturnParameterType.

Test

File: src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/PowerPlatformConnectorTests.cs

Added four direct unit tests for GetConnectorType:

  • GetConnectorType_MissingValuePath_ReturnsNull — exact AzDO repro shape ({"otherProperty":"value"} with valuePath="Fields").
  • GetConnectorType_EmptyStringValue_ReturnsNull — empty StringValue.
  • GetConnectorType_ValuePathResolvesToNull_ReturnsNull — {"Fields":null}.
  • GetConnectorType_ValidSchemaAtValuePath_ReturnsConnectorType — happy path, guards against the early-return swallowing valid schemas.

All four pass. Pre-existing GetConnectorType_* and dynamic-schema tests (DVDynamicReturnType, ServiceNowOutputType_GetRecord, ExcelOnlineAddRowV2_ItemParamHasDynamicSchema) continue to pass unchanged.

When a connector's x-ms-dynamic-schema or x-ms-dynamic-properties sub-call
returns a 200 OK response whose body is empty or whose valuePath doesn't
resolve, ExtractFromJson yields default(JsonElement) (ValueKind ==
Undefined). GetConnectorType then forwarded that default value to
GetConnectorTypeInternal, which called je.ToString() (producing "") and
passed it to OpenApiStringReader.ReadFragment<OpenApiSchema>. Deep inside
Microsoft.OpenApi.Readers.OpenApiTextReaderReader.LoadYamlDocument,
YamlStream.Documents.First() was invoked on an empty document stream and
threw InvalidOperationException("Sequence contains no elements"). The
exception surfaced out of GetConnectorReturnTypeAsync /
GetConnectorTypeAsync as an opaque LINQ failure with no hint that the
real cause was a dynamic-schema payload that didn't contain the expected
property.

Real-world repro: Azure DevOps GetQueryResultsV2 declares its items as
x-ms-dynamic-properties with operationId=GetQueryResultWorkItemSchema and
itemValuePath=Fields. For some valid query shapes (e.g. queries whose
saved columnOptions don't map to populated Fields), the sub-call returns
200 OK with a body that has no usable value at Fields. The static 5-layer
recursion through GetConnectorTypeInternalAsync then hit LoadYamlDocument
and failed with "Sequence contains no elements" instead of simply
falling back to the static return type.

# Fix

File: src/libraries/Microsoft.PowerFx.Connectors/ConnectorFunction.cs

GetConnectorType now checks JsonElement.ValueKind against Undefined /
Null before delegating to GetConnectorTypeInternal and returns null when
the extracted element is not usable. The two async callers
(GetConnectorSuggestionsFromDynamicSchemaAsync and
GetConnectorSuggestionsFromDynamicPropertyAsync) recognize the new null
return, log a warning identifying the offending valuePath /
itemValuePath, and return null themselves. The rest of the recursion
already treats null as "no dynamic extension resolved" (see
GetConnectorTypeInternalAsync line 683), so null propagates cleanly all
the way back to GetConnectorReturnTypeAsync callers that can then fall
back to the static ReturnParameterType.

# Test

File: src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/PowerPlatformConnectorTests.cs

Added four direct unit tests for GetConnectorType:
- GetConnectorType_MissingValuePath_ReturnsNull — exact AzDO repro shape
  ({"otherProperty":"value"} with valuePath="Fields").
- GetConnectorType_EmptyStringValue_ReturnsNull — empty StringValue.
- GetConnectorType_ValuePathResolvesToNull_ReturnsNull — {"Fields":null}.
- GetConnectorType_ValidSchemaAtValuePath_ReturnsConnectorType — happy
  path, guards against the early-return swallowing valid schemas.

All four pass. Pre-existing GetConnectorType_* and dynamic-schema tests
(DVDynamicReturnType, ServiceNowOutputType_GetRecord,
ExcelOnlineAddRowV2_ItemParamHasDynamicSchema) continue to pass unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@EricBuist EricBuist requested a review from a team as a code owner April 20, 2026 19:33
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.

1 participant