Skip to main content

dora-lei-check

Find the LEIs that will get your DORA Register of Information rejected — before you submit it, on your own machine.

pip install dora-lei-check
dora-lei-check register.zip

The problem this solves

A lapsed LEI is perfectly well-formed. It is 20 characters, it passes the ISO 17442 checksum, and it sails through offline XBRL validation. Then you submit, and days later the register comes back:

[EBA.VR_71] LEI 984500914ED4D50AZ405 needs to be a valid one according to
the GLEIF databases.

The LEI-versus-GLEIF check is an external lookup. The ESAs run it on their side, after submission, against the live GLEIF register. Until you get the rejection, you are guessing — and each round trip through your NCA burns days you do not have inside a reporting window.

This tool runs that same lookup locally, before you submit.

$ dora-lei-check register.zip

LEI                   VERDICT     GLEIF STATUS      LEGAL NAME
--------------------  ----------  ----------------  ----------------------
254900ZD9J74PNOI5L11  NOT ISSUED  LAPSED            VARANDO LTD
5493001KJTIIGC8Y1R12  OK          ISSUED            Bloomberg Finance L.P.
5493001KJTIIGC8Y1R13  INVALID     invalid checksum  —
984500914ED4D50AZ405  NOT ISSUED  LAPSED            BONOCAP LTD

4 distinct LEI(s): 1 OK, 3 failing, 0 unverified

These will be rejected at submission:
  254900ZD9J74PNOI5L11  NOT ISSUED found in b_05.01.csv:0030  [EBA.VR_77]
  5493001KJTIIGC8Y1R13  INVALID    found in b_05.01.csv:0010  [EBA.VR_71]
  984500914ED4D50AZ405  NOT ISSUED found in b_05.01.csv:0010  [EBA.VR_71]

It tells you the rule code you are about to receive, not just that something is wrong.

📄 What each LEI rejection error means, and how to fix it

Errors it catches before the regulator does

If you are here because you already received one of these, this is the tool that stops it happening again:

Rule Message Where
EBA.VR_2 LEI [LEI] needs to be a valid one according to the GLEIF databases B.01.01, column 0010
EBA.VR_12 LEI [LEI] needs to be a valid one according to the GLEIF databases B.01.02, column 0010
EBA.VR_23 LEI [LEI] needs to be a valid one according to the GLEIF databases B.01.02, column 0060
EBA.VR_71 LEI [LEI] needs to be a valid one according to the GLEIF databases B.05.01, column 0010
EBA.VR_77 LEI [LEI] needs to be a valid one according to the GLEIF databases B.05.01, column 0030

It also catches the malformed and missing identifiers behind v8826_m (incorrect LEI in table), v8891_m (wrong LEI format in table), and ICTO007 (no valid or existing LEI has been found for this entity).

Related codes it does not cover yet: VR_16 (country code versus the LEI certificate), and VR_72 / VR_78 (EUID against BRIS). See what it does not do.

Why this is worth checking

In the ESAs' dry run, 93.5% of submissions carried at least one data error and only 6.5% passed all 116 data-quality checks. In the first live cycle, supervisors reported missing or invalid LEIs in roughly a third of submissions — among the most common hard-rejection causes. The 2026 cycle tightened the checks further: a register accepted one year can be rejected the next.

Registration status is not static. An LEI that was ISSUED when you built the register can be LAPSED by the time you submit it, because the provider simply did not renew. Nothing in your file changes. The verdict does.

Your register never leaves your machine

This matters more than it sounds. A Register of Information is a complete map of your ICT third-party estate — every provider, every contractual arrangement, every criticality assessment. The other pre-submission validators are hosted web tools: you upload that file to someone else's server.

dora-lei-check reads the register locally. The only thing that crosses the network is the public 20-character LEI codes, sent to GLEIF's free public API. With --offline and GLEIF's daily golden-copy file, nothing crosses the network at all.

Install

pip install dora-lei-check

Python 3.10+. Zero dependencies — nothing for your security team to review.

Use

dora-lei-check register.zip           # a submitted xBRL-CSV package
dora-lei-check ./templates/           # a folder of RoI CSV templates
dora-lei-check b_05.01.csv            # a single template

dora-lei-check register.zip --json    # machine-readable, for pipelines
dora-lei-check register.zip --offline gleif-golden-copy.csv   # no network at all
dora-lei-check register.zip --columns 0010 0030               # narrow the scan
Exit code Meaning
0 every LEI is issued and active
1 at least one LEI will be rejected
2 some LEIs could not be verified — a network failure is never silently a pass
3 the register could not be read

Exit 1 makes it a pre-submission gate in CI. Results are cached on disk, so re-runs during a correction cycle are instant.

As a library

from pathlib import Path
from dora_lei_check import Report, extract, fetch, judge

report = Report([judge(c, fetch(c.lei)) for c in extract(Path("register.zip"))])
for failure in report.failures:
    print(failure.lei, failure.verdict.value, failure.rules)

What it does and does not do

Does: finds every LEI-shaped value anywhere in the register, validates ISO 17442 format and the mod-97 checksum offline, resolves each one against GLEIF, reports anything that is not ISSUED, and names the EBA rule code it will trigger.

Does not: validate the XBRL itself. Use Arelle for the technical and DPM layers — it is free, excellent, and this is not a replacement for it. Cross-table business rules and EUID-versus-BRIS are not covered.

To be precise about the overlap, because precision is the point: Arelle's validate/EBA plugin does check LEIs — format and checksum, entirely offline, and only for context entity identifiers. It contains no GLEIF capability whatsoever. A lapsed LEI passes Arelle and fails your submission. That gap is the entire reason this exists.

Accuracy note

LEIs are located by shape and checksum rather than by a taxonomy field map, so the tool keeps working across EBA taxonomy versions instead of breaking on each release. The trade-off: a 20-character alphanumeric string that is not an LEI could in principle pass the checksum. Every finding is reported with its file, column and row so you can see exactly what was matched, and --columns narrows the scan when you want it exact.

Rule codes are only shown when the table and column are unambiguous. A wrong rule code would be worse than none.

Contributing

If your register failed on something this tool did not catch, open an issue and say what the rejection said. That feedback decides what gets built next.

License

MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dora_lei_check-0.3.0.tar.gz (19.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dora_lei_check-0.3.0-py3-none-any.whl (15.2 kB view details)

Uploaded Python 3

File details

Details for the file dora_lei_check-0.3.0.tar.gz.

File metadata

  • Download URL: dora_lei_check-0.3.0.tar.gz
  • Upload date:
  • Size: 19.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.9

File hashes

Hashes for dora_lei_check-0.3.0.tar.gz
Algorithm Hash digest
SHA256 571bdd9505c788d31ae5fb6aff260fdf235aabcf024339ab72757d886e3593bc
MD5 db1c1c7f3e787bb48f9fc1a98d8ced56
BLAKE2b-256 bf9000ca7ce911ceb242ca19cd00546971acd446e0dceab12611ed0cef7ed1b1

See more details on using hashes here.

File details

Details for the file dora_lei_check-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: dora_lei_check-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 15.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.9

File hashes

Hashes for dora_lei_check-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 359a4d202bcb5b65dd6bb89be81da568494ec1fabc5673930f580239ec1c50e2
MD5 cd947add193529cf3ef76470998f492f
BLAKE2b-256 e93ce3b0b5e53b5a0d2cbb2f791677b54c81a29867d5f829f36456e06867d9e5

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page