← Syamjith NK

10 September 2026 · Syamjith NK

I scanned 341 Arabic datasets to see if the corruption reaches training data

Three posts on this blog argue that the standard way to make Arabic work in Python corrupts it. That argument has a hole in it: all the evidence was about rendering code. A reversed chart label is embarrassing and fixable. But the same recipe run once, before a file is written, bakes the damage in permanently.

If that ever happened upstream of a training corpus, every model trained on it learned from text no Arabic reader would accept. I could not find anyone who had checked, so I did.

Method, and why the first answer was wrong

I pulled rows for every Arabic dataset I could find on the Hugging Face Hub through the datasets-server API and scanned them with my own linter. 341 datasets.

The first run said 35.6% of an Islamic heritage OCR corpus was corrupted. Two others came back at 27% and 5%. That is a headline. I nearly had one.

Then I printed the characters it was objecting to:

U+FD3F  ﴿  ORNATE RIGHT PARENTHESIS
U+FD3E  ﴾  ORNATE LEFT PARENTHESIS
U+FD40  ﵀  ARABIC LIGATURE RAHIMAHU ALLAAH

Those are not damage. `﴾ ﴿` is how you enclose a Quranic quotation, and `﵀` is an honorific. People type them deliberately. My tool was flagging them because Arabic Presentation Forms-A is interleaved: the positional glyph forms and ordinary semantic characters share one block, and I had excluded only the word ligatures at the end of it.

So on Islamic heritage text, which is a large share of all Arabic corpora, the tool was confidently wrong, in the direction that publicly accuses somebody else's dataset. The fix was to stop tabulating ranges and derive the class from the Unicode character name: a shaping artefact is exactly a codepoint named ... ISOLATED/INITIAL/MEDIAL/FINAL FORM. Everything else in the block is deliberate, and new Unicode additions classify themselves.

All three datasets then read 0%.

The result

276 datasets readable. 26,318 rows. 119,517 text fields.

Twenty-one had any finding at all, and twenty of those were a single stray presentation form in otherwise correct text, most often U+FE91 BEH INITIAL FORM. That is copy-paste out of a PDF, or OCR residue. It is still wrong, because a tokenizer treats and ب as different tokens, so the same word splits into different vocabulary entries and exact-match lookup fails silently. But it is not the recipe.

One dataset was the recipe.

One dataset, 100%

Yousefmd/arabic_ocr_dataset — every text field, 400 out of 400 across four sample windows, 23 to 29 presentation forms per label. A sample row:

ﺑﺪﺃﺕ ﻗﺮﺍﺀﺓ ﺍﻟﺼﻔﺤﺎﺕ ﺍﻷﻭﻟﻰ ﻋﻠﻰ ﻧﻐﻤﺎﺕ

The intended text is بدأت قراءة الصفحات الأولى على نغمات. Two things happened to it: every letter was replaced by its contextual glyph form, and then the words were written in visual order. INITIAL, MEDIAL, FINAL and ISOLATED forms all present together. That is the complete signature.

It matters more than its size because of which field is damaged. This is an OCR dataset, so text is the ground truth. A model trained on it learns to emit presentation forms in visual order, and then fails string comparison against real Arabic even when it read the image correctly. That is the path from a rendering bug into model weights, observed rather than argued for.

Now the honest part: that dataset has 17 downloads. This shows the mechanism reaches training data. It is not evidence that widely-used Arabic corpora are affected, and I am not going to write it as though it were.

What this does not show

65 datasets could not be read, and the viewer fails most often on the largest corpora. So this covers the mid and small end of the distribution well and the head of it poorly. Nothing here reaches web-scale pretraining data. A hundred rows per dataset also cannot find a defect confined to a rare subset.

An earlier version of this audit claimed 121 datasets were unreadable. 61 of those were rate-limit errors caused by my own request rate. A coverage caveat built out of your own impatience is not a caveat, it is a mistake; a slower second pass recovered them.

The thing I would tell anyone doing this

The audit was one command away from being published with three named datasets and a percentage next to each. What stopped it was reading the flagged characters instead of trusting the count.

If you point a measurement tool at somebody else's work, check its output against text you can actually read before the number leaves your machine. A false positive costs them a public accusation and costs you the only thing that makes the measurement worth anything.