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.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dora_lei_check-0.2.0.tar.gz.
File metadata
- Download URL: dora_lei_check-0.2.0.tar.gz
- Upload date:
- Size: 17.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d9df0483f8cbf53cc521d454fe2e8f65a40bb804184517c481c7cd88d5125d8
|
|
| MD5 |
deb75bf8f6962cbcb3cdef457b5bfacf
|
|
| BLAKE2b-256 |
e3f01f381caa0dd9419d9abb89717292e90bc8e2a15bd2fa697f4725f3b7ea62
|
File details
Details for the file dora_lei_check-0.2.0-py3-none-any.whl.
File metadata
- Download URL: dora_lei_check-0.2.0-py3-none-any.whl
- Upload date:
- Size: 14.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1df98956b9b0fdafdcad7fd53292646e2ec3cdb569c7838d03d858d06890fae0
|
|
| MD5 |
9e14fa91e0a0f755000d8cb3ca632921
|
|
| BLAKE2b-256 |
110d7cecee2e6fab22adea0243f8fc67e51183c9dab7df624e780d2413f2396b
|