Skip to content

Update breaks (500 error) when bundle was invalid #284

@Reinaard

Description

@Reinaard

When a resource/bundle is invalid, it gives a 500 internal server error instead of nicer error handling

To Reproduce

  1. POST invalid Endpoint to FHIR store like (everything is accidentally within "meta"):
{
    "resourceType": "Endpoint",
    "meta": {
        "versionId": "1",
        "lastUpdated": "2025-11-27T09:31:25.541+00:00",
        "status": "entered-in-error",
        "connectionType": {
            "system": "http://example.org/connection-type",
            "code": "hl7-fhir-messaging",
            "display": "HL7 FHIR Messaging"
        },
        "name": "Test BV",
        "payloadType": [
            {
                "coding": [
                    {
                        "system": "http://example.org/payload-type",
                        "code": "application/fhir+json",
                        "display": "FHIR XML"
                    }
                ]
            }
        ],
        "payloadMimeType": [
            "application/fhir+xml"
        ],
        "address": "http://lmr-noord:9500/fhir",
        "header": [
            "Authorization: Bearer token"
        ]
    },
    "search": {
        "mode": "match"
    }
}
  1. GET the new Endpoint and notice the small body:
{
      "fullUrl": "http://localhost:9504/fhir/Endpoint/7",
      "resource": {
        "resourceType": "Endpoint",
        "id": "7",
        "meta": {
          "versionId": "1",
          "lastUpdated": "2025-12-09T15:20:35.421+00:00"
        }
      },
      "search": {
        "mode": "match"
      }
    },
  1. Go to mcsd-update-client and update resource
  2. We get an 500 internal server error:
INFO:     185.93.2.245:51378 - "POST /update_resources HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py", line 403, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 1134, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 113, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 186, in __call__
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.11/site-packages/opentelemetry/instrumentation/asgi/__init__.py", line 743, in __call__
    await self.app(scope, otel_receive, otel_send)
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 63, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 716, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 736, in app
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 290, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 125, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 111, in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 391, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 292, in run_endpoint_function
    return await run_in_threadpool(dependant.call, **values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/concurrency.py", line 38, in run_in_threadpool
    return await anyio.to_thread.run_sync(func)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/anyio/to_thread.py", line 56, in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 2485, in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 976, in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/src/app/routers/update_router.py", line 35, in update_all_directories
    return [service.update(directory, since, ura_whitelist) for directory in directories]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/src/app/routers/update_router.py", line 35, in <listcomp>
    return [service.update(directory, since, ura_whitelist) for directory in directories]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/src/app/services/update/update_client_service.py", line 166, in update
    self.update_resource(directory, res.value, cache_service, since, ura_whitelist)
  File "/src/app/services/update/update_client_service.py", line 209, in update_resource
    next_params, history = directory_fhir_api.get_history_batch(
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/src/app/services/api/fhir_api.py", line 199, in get_history_batch
    page_bundle = self.__fhir_service.create_bundle(response.json())
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/src/app/services/fhir/fhir_service.py", line 46, in create_bundle
    return create_bundle(data, self.fill_required_fields)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/src/app/services/fhir/bundle/parser.py", line 31, in create_bundle
    return Bundle.model_validate(data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pydantic/main.py", line 716, in model_validate
    return cls.__pydantic_validator__.validate_python(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 2 validation errors for Bundle
entry.0.resource.connectionType
  Field required [type=missing, input_value={'id': '7', 'meta': {'ver...09T15:20:35.421+00:00'}}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.12/v/missing
entry.0.resource.payloadType
  Field required [type=missing, input_value={'id': '7', 'meta': {'ver...09T15:20:35.421+00:00'}}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.12/v/missing
  1. Not delete the invalid Endpoint using the id in the FHIR store
  2. Try update resource again from mcsd_update_client
  3. Still 500 internal server error

Expected behavior:

  • Nicer error handling, application should not break!
  • After deleting the invalid Endpoint, the error should disappear

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions