Skip to content

Facet label mapping crashes with KeyError when label_map lacks a bucket key (missing fallback in get_labelled_values) #3257

@Samk13

Description

@Samk13

Package version (if known): v13 v14

Describe the bug

Problem

I have duplicate funders coming from diffrent sources in my instance, same funders diffrent ids one has ROR the other has "diarienummer"
so I updated my awards that points to the later funders to adapt the ror id instead
now i have double funders when I search so I deleted the later ones with the script included here.
now when I enter the awards UI I get something went wrong with long console error "see below"
fixing the linehere to safly get the key with label_map.get(key) Instead of brittlely getting it with label_map[key]

I also created a migration script to search for all records and drafts and replace the depreacted IDs. However, the UI still failing, UI should remain functional even if an ID is missing.

Steps to Reproduce

  1. create records with awards that related to old funders
  2. update the awards to link to new funders id
  3. delete the old funders
  4. reindex everything invenio rdm-records rebuild-index invenio rdm rebuild-all-indices -o awards, funders, vocabularies
  5. go to deposit page and load awards
  6. Observe a 500 error with a traceback ending in KeyError: '<missing-key>'.## Expected behaviorFacet label resolution should never crash. Missing labels should fall back to the bucket key. Example safe behavior:
    label = label_map.get(key, key)
Error logs
127.0.0.1 - - [03/Dec/2025 10:52:08] "GET /api/awards?q=&sort=bestmatch&page=1&size=5 HTTP/1.1" 500 -
Traceback (most recent call last):
  File ".venv/lib/python3.12/site-packages/flask/app.py", line 1536, in __call__
    return self.wsgi_app(environ, start_response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/werkzeug/middleware/proxy_fix.py", line 183, in __call__
    return self.app(environ, start_response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/werkzeug/middleware/dispatcher.py", line 81, in __call__
    return app(environ, start_response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/flask/app.py", line 1536, in __call__
    return self.wsgi_app(environ, start_response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/werkzeug/middleware/proxy_fix.py", line 183, in __call__
    return self.app(environ, start_response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/flask/app.py", line 1514, in wsgi_app
    response = self.handle_exception(e)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/flask/app.py", line 1511, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/flask/app.py", line 919, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/flask_resources/resources.py", line 65, in view
    return view_meth()
           ^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/flask_resources/content_negotiation.py", line 116, in inner_content_negotiation
    return f(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/flask_resources/parsers/decorators.py", line 51, in inner
    return f(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/flask_resources/parsers/decorators.py", line 51, in inner
    return f(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/flask_resources/responses.py", line 39, in inner
    res = f(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/invenio_records_resources/resources/records/resource.py", line 86, in search
    return hits.to_dict(), 200
           ^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/invenio_records_resources/services/records/results.py", line 252, in to_dict
    if self.aggregations:
       ^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/invenio_records_resources/services/records/results.py", line 194, in aggregations
    return self._results.labelled_facets.to_dict()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/invenio_records_resources/services/records/facets/response.py", line 81, in labelled_facets
    self._labelled_facets[name] = facet.get_labelled_values(
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.12/site-packages/invenio_records_resources/services/records/facets/facets.py", line 66, in get_labelled_values
    "label": label_map[key],
             ^^^^^^^^^^^^^^^
KeyError: '202100-5000'
The script used to delete funders:
# invenio shell

# Script to delete funders based on IDs listed in a YAML file.

from pathlib import Path

import yaml
from invenio_access.permissions import system_identity
from invenio_records_resources.proxies import current_service_registry

funders_service = current_service_registry.get("funders")

yaml_path = Path("app_data/vocabularies/kth_funders.yaml")

if not yaml_path.exists():
    raise FileNotFoundError(
        "YAML file not found at app_data/vocabularies/kth_funders.yaml"
    )

with yaml_path.open() as f:
    items = yaml.safe_load(f)

for entry in items:
    f_id = entry.get("id")
    if not f_id:
        continue

    try:
        funders_service.delete(system_identity, f_id)
        print(f"Deleted funder {f_id}")
    except Exception as e:
        print(f"Failed to delete {f_id}: {e}")

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