microsoft / microsoft/fhir-server

NullReferenceException in ParameterCompatibleFilter.ParseResource() during resource validation

Open
#5,114 0 comments 1 reaction 1 assignee View on GitHub

Nobody has claimed this yet.

Bug nullreferenceexception parameters validation
Dominant language
TSQL
Stars
1.4k
Forks
592
Avg merge
2d 7h
Merged PRs (30d)
41

Description

🐛 Bug Report

Description

Resource validation operations are failing with NullReferenceException in the ParameterCompatibleFilter.ParseResource() method when processing Parameters resources that don't contain the expected "resource" parameter.

Error Details

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.Health.Fhir.Api.Features.Filters.ParameterCompatibleFilter.ParseResource(Resource resource)
   in /_/src/Microsoft.Health.Fhir.Shared.Api/Features/Filters/ParameterCompatibleFilter.cs:line 26
   at Microsoft.Health.Fhir.Api.Features.Filters.ValidateResourceTypeFilterAttribute.OnActionExecuting(ActionExecutingContext context)
   in /_/src/Microsoft.Health.Fhir.Shared.Api/Features/Filters/ValidateResourceTypeFilterAttribute.cs:line 33

Root Cause Analysis

The issue occurs in ParameterCompatibleFilter.cs line 26:

protected Resource ParseResource(Resource resource)
{
    if (_allowParametersResource && resource.TypeName == KnownResourceTypes.Parameters)
    {
        resource = ((Parameters)resource).Parameter.Find(param => param.Name.Equals("resource", StringComparison.OrdinalIgnoreCase)).Resource;  // LINE 26 - NULL REFERENCE
    }

    return resource;
}

The issue occurs when:

  1. resource.TypeName == KnownResourceTypes.Parameters is true
  2. ((Parameters)resource).Parameter.Find(...) returns null because:
    • No parameter with name "resource" exists
    • The Parameter collection is null
    • The found parameter has a null Resource property
  3. Accessing .Resource on a null parameter causes the NullReferenceException

Reproduction Steps

  1. Create a Parameters resource with either:
    • No parameter named "resource"
    • A parameter named "resource" with a null Resource property
    • A null Parameter collection
  2. Send this Parameters resource through the validation pipeline
  3. The NullReferenceException will be thrown at line 26

Minimal Reproduction Example

var parameters = new Parameters();
parameters.Parameter = new List<Parameters.ParameterComponent>
{
    new Parameters.ParameterComponent
    {
        Name = "resource",
        Resource = null  // This causes the NullReferenceException
    }
};

// This will throw NullReferenceException when processed by ParameterCompatibleFilter

Proposed Fix

Add defensive null checking in the ParseResource method:

protected Resource ParseResource(Resource resource)
{
    if (_allowParametersResource && resource?.TypeName == KnownResourceTypes.Parameters)
    {
        var parameters = (Parameters)resource;
        var resourceParam = parameters.Parameter?.Find(param => param.Name.Equals("resource", StringComparison.OrdinalIgnoreCase));
        
        if (resourceParam?.Resource != null)
        {
            resource = resourceParam.Resource;
        }
        // If no resource parameter found or it's null, return the original Parameters resource
        // This maintains backward compatibility while preventing the crash
    }

    return resource;
}

Alternative Solution

Add validation in the calling methods to handle null results from ParseResource():

public override void OnActionExecuting(ActionExecutingContext context)
{
    // ... existing code ...
    
    if (context.ActionArguments.TryGetValue(KnownActionParameterNames.Resource, out var parsedModel))
    {
        var resource = ParseResource((Resource)parsedModel);
        if (resource == null)
        {
            throw new ResourceNotValidException("Failed to extract resource from Parameters");
        }
        
        ValidateType(resource, (string)actionModelType);
    }
}

Test Cases to Add

[Fact]
public void ParseResource_WithNullParameterResource_ShouldNotThrow()
{
    var parameters = new Parameters();
    parameters.Parameter = new List<Parameters.ParameterComponent>
    {
        new Parameters.ParameterComponent { Name = "resource", Resource = null }
    };
    
    var filter = new TestParameterCompatibleFilter(allowParametersResource: true);
    var result = filter.ParseResource(parameters);
    
    Assert.NotNull(result); // Should not throw NullReferenceException
}

[Fact]
public void ParseResource_WithMissingResourceParameter_ShouldNotThrow()
{
    var parameters = new Parameters();
    parameters.Parameter = new List<Parameters.ParameterComponent>
    {
        new Parameters.ParameterComponent { Name = "otherParam", Value = new FhirString("test") }
    };
    
    var filter = new TestParameterCompatibleFilter(allowParametersResource: true);
    var result = filter.ParseResource(parameters);
    
    Assert.NotNull(result); // Should not throw NullReferenceException
}

Impact

  • Severity: High - Validation operations fail with HTTP 500 errors
  • Affected Operations: Resource validation endpoints that accept Parameters resources
  • Client Impact: Any client sending Parameters resources without proper "resource" parameter structure

Backward Compatibility

The proposed fix maintains backward compatibility by:

  • Still extracting the inner resource when properly structured Parameters are provided
  • Gracefully handling malformed Parameters by returning the original Parameters resource
  • Not changing the method signature or expected behavior for valid inputs

This is a defensive programming issue where the code assumes Parameters resources always contain a valid "resource" parameter. The fix should prevent crashes while maintaining existing functionality.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.