Skip to content
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

Bundle profile validation incorrectly generates "The entry resource did not match any of the allowed profiles" error message #1902

Open
rettema opened this issue Feb 13, 2025 · 4 comments

Comments

@rettema
Copy link
Contributor

rettema commented Feb 13, 2025

Issue

Validation of the Bundle pas-request-bundle.json is generating the following error message:

The entry resource did not match any of the allowed profiles (Type Claim: http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-claim-update, http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-claim). Location: Bundle.entry[0].resource/*Claim/HomecareAuthorizationExample*/ (line 15, col 6).

The Bundle.entry[0].resource is a Claim that does validate against the expected target profile "http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-claim"; meaning, there are only information and warning validation messages generated. As such, it should be a valid Bundle.entry.resource for the overall validation of the Bundle against the profile "http://hl7.org/fhir/us/davinci-pas/StructureDefinition/profile-pas-request-bundle".

Analysis

I have reviewed the current validation logic in the core library code and have the following analysis:

Validation of a profiled Bundle resource where the Bundle.entry.resources are required to conform to specific resource profile(s) involves applying validation of the Bundle.entry.resource against all specified target profiles. If the resource validates against any one of these target profiles, then that satisfies the validation of that entry.resource for the overall Bundle validation.

This particular logic is contained in the InstanceValidator class validateContains method where each target profile is iterated over and individually applied to the entry.resource. The validation is applied by calling the method validateResource where its logic returns a boolean that is used to determine the conformance to the target profile: true for valid, false for invalid. Review of the validateResource method shows that the boolean returned value does not accurately reflect the validation result. The main validation logic that calls the validateResource method ignores the boolean value and instead simply aggregates the generated validation messages.

Proposed Solution

The solution to the profiled Bundle resource validation logic is to replace the check of the returned validateResource boolean value with a check of the aggregated validation messages for the absence or presence of any error or fatal issues.

Current Logic

The currently InstanceValidator.validateContains logic:

            for (CanonicalType u : typeForResource.getProfile()) {              
              b.append(u.asStringValue());
              long t = System.nanoTime();
              StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, u.asStringValue());
              timeTracker.sd(t);
              if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
                  profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special == null ? "??" : special.toHuman(), u.asStringValue())) {
                trackUsage(profile, valContext, element);
                List<ValidationMessage> perrors = new ArrayList<>();
                errorsList.add(perrors);
                if (validateResource(hc, perrors, resource, element, profile, idstatus, stack, pct, mode, false, special == SpecialElement.CONTAINED)) {
                  bm.append(u.asStringValue());
                  matched++;
                }
              } else {
                ok = false;
              }
            }

Proposed New Logic

            for (CanonicalType u : typeForResource.getProfile()) {              
              b.append(u.asStringValue());
              long t = System.nanoTime();
              StructureDefinition profile = this.context.fetchResource(StructureDefinition.class, u.asStringValue());
              timeTracker.sd(t);
              if (rule(errors, NO_RULE_DATE, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(),
                  profile != null, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOPROFILE_TYPE, special == null ? "??" : special.toHuman(), u.asStringValue())) {
                trackUsage(profile, valContext, element);
                List<ValidationMessage> perrors = new ArrayList<>();
                errorsList.add(perrors);
                // Check perrors for no error or fatal issues
                // This is necessary because the validateResource method boolean return value
                // cannot be trusted to accurately reflect the results of the validation.
                boolean pOk = true;
                validateResource(hc, perrors, resource, element, profile, idstatus, stack, pct, mode, false, special == SpecialElement.CONTAINED);
                for (ValidationMessage vm : perrors) {
                  pOk = vm.getLevel() != IssueSeverity.ERROR && vm.getLevel() != IssueSeverity.FATAL && pOk; 
                }
                if (pOk) {
                  bm.append(u.asStringValue());
                  matched++;
                }
              } else {
                ok = false;
              }
            }
@grahamegrieve
Copy link
Collaborator

Thanks for the submission. I haven't started thinking about this, but whatever, it will require test cases. Firstly, a simple-as-possible test case showing the validator is broken, and second, what happens with existing test cases?

@rettema
Copy link
Contributor Author

rettema commented Feb 13, 2025

Let me see what I can come up with for the first test case.

@rettema
Copy link
Contributor Author

rettema commented Feb 17, 2025

Ok. I've got the fhir-test-cases configured in my org.hl7.fhir.core IDE and I've played with this scenario for a while on Friday.

I've narrowed down the issue with the (FHIR R4) Da Vinci PAS IG v2.1.0 Claim profile defining an extension using the cross-version extension http://hl7.org/fhir/5.0/StructureDefinition/extension-Claim.encounter.

So, my original analysis was incorrect. The issue is with the (current lack of) support for cross-version extensions (at least with the the Da Vinci PAS IG v2.1.0 Claim definition).

I have created a test case and simplified artifacts that demonstrate the problem. See attached zip file re-test-case-1902.zip

@grahamegrieve
Copy link
Collaborator

ok. I'll revisit this one cross-version extensions are properly handled infra structurally

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

No branches or pull requests

2 participants