Page MenuHomePhabricator

🧱 Unable to use Wikidata REST API to create statements: "error": "rest-write-denied" (due to globally blocked IP)
Closed, ResolvedPublicBUG REPORT

Description

Hi there! We're running into a puzzling issue that I hope somebody here can shed some light on.

We're building a tool (https://loom.everypolitician.org/ | https://github.com/opensanctions/poliloom/) that extracts statements on politicians from Wikipedia and the wider web, offers those to evaluators and on confirmation, pushes these statements to Wikidata. This makes use of the mediawiki OAuth system so people update Wikidata on their own account.

I'm running into the problem that I can't push Wikidata statements from our production environment, while the same code works fine in development. In production, we get a HTTP 403 JSON response:

{"error":"rest-write-denied","httpCode":403,"httpReason":"Forbidden"}

Our OAuth2 app settings are exactly the same for production and development.

I've ran the production setup locally to make sure there's no problem there, that works. Checked what tokens went out on the API request, both local development and production send the same access tokens, with the same permissions and user information, with only the AUD related claims differing, as expected.

I've tracked this issue to logic in Wikibase that returns this 403 on UseCaseError::PERMISSION_DENIED_UNKNOWN_REASON which does not provide much insight. When I look through the Wikibase source for this UseCaseError, I see some references to "protected" pages, however when I check entities that I'm trying to create statements for, I see no indication of them being protected. For example entity Q32965:

Failed to create statement for entity Q32965 with property P39: HTTP 403 - {"error":"rest-write-denied","httpCode":403,"httpReason":"Forbidden"}
Failed to push PositionEvaluation 5e8bc92d-1856-4c04-818f-05bec5aa725a to Wikidata

What is happening here? Why are edits from my development machine accepted, but edits coming from our production server denied? The software is doing the exact same thing, the OAuth2 configuration is exactly the same. Is our production app lacking permissions? And how do I figure out if Wikidata items are protected?

Thanks in advance for any help!

Event Timeline

That codebase seems to set ./poliloom/poliloom/api/auth.py: self.user_agent = "PoliLoom API/0.1.0" (for anyone digging in logs)

https://www.wikidata.org/wiki/Q32965?action=info
https://www.wikidata.org/w/index.php?title=Special:Log&type=protect&page=Q32965

^ Allow all users (infinite) means you can't edit anon, but logged in is fine (with no other rights).

Can you confirm the edits coming from your production server are actually correctly logged in/sending the expected tokens?

Can you confirm the edits coming from your production server are actually correctly logged in/sending the expected tokens?

Yes, I checked what tokens went out on the API requests, both local development and production send the same access tokens, with the same permissions and user information, with only the AUD related claims differing, as expected.

Here's the relevant debug logs from both production and development. They include the request body, and (expired) tokens.

I also tested using the production setup with my localhost credentials by setting up a reverse proxy on localhost. The production server also gets the rest-write-denied response when using the localhost credentials, so I don't think credentials are the problem.

Where is the server running? Some public cloud? Presuming you have a static IP on it?

The server is running in the Hetzner Falkenstein datacenter in Germany.

IPv4: 148.251.131.144
IPv6: 2a01:4f8:210:30ce::2

This might have something to do with it.

https://meta.wikimedia.org/wiki/Special:BlockList?wpTarget=148.251.131.14

The user 148.251.131.144 is blocked globally.

  • Date: 8 May 2025
  • Target: 148.251.0.0/16
  • Expires: 8 May 2026
  • Blocks: editing, anon only, account creation
  • Reason: Open proxy

Woah, great find! That looks like it's the problem yeah.

Can we be whitelisted, or could that block rule be made more specific? Right now it's blocking a whole /16 in the Hetzner network, 65,534 hosts.

Unfortunately a lot of bad traffic comes from "cheap" provider networks like Hetzner.

https://meta.wikimedia.org/wiki/Special:MyLanguage/NOP
https://meta.wikimedia.org/wiki/WM:OP/H

https://meta.wikimedia.org/wiki/Special:MyLanguage/Stewards/Wizard would be the appeal process

If you have a static IP, you should have a reasonable case... Or are you able to force traffic from your side over IPv6?

Yes we have a static address.

I'll submit an appeal first, if that for some reason does not work out, I can still look into the possibility of forcing IPv6 traffic.

Thank you very much for your help in figuring this out, it's much appreciated!

Aklapper renamed this task from Unable to use Wikidata REST API to create statements: "error": "rest-write-denied" to Unable to use Wikidata REST API to create statements: "error": "rest-write-denied" (due to globally blocked IP).Sep 20 2025, 4:23 PM

Sidenote: the error message could be much clearer here and specify why the write is denied.

Thank you all for your help, we're no longer blocked from using the Wikidata API, our initial issue is resolved.

Sidenote: the error message could be much clearer here and specify why the write is denied.

I couldn't agree more. Also the constant UseCaseError::PERMISSION_DENIED_UNKNOWN_REASON that I found when I looked for this error put me on the wrong track.

A follow up task should probably be filed to have this fixed/improved in Wikibase

I'm glad the issue was resolved for @Monneyboi, and apologies for getting to it this late. I'll add this in our backlog to see to us getting around to improving the error message

ItamarWMDE renamed this task from Unable to use Wikidata REST API to create statements: "error": "rest-write-denied" (due to globally blocked IP) to 🧱 Unable to use Wikidata REST API to create statements: "error": "rest-write-denied" (due to globally blocked IP).Dec 1 2025, 12:41 PM
ItamarWMDE removed ItamarWMDE as the assignee of this task.
ItamarWMDE moved this task from Doing to To Do on the Wikibase Reuse Team (Sprint 58) board.
ItamarWMDE subscribed.