Add-on upload returns "Bad Request" (400) even for a minimal one-file add-on

Uploading an add-on at https://ankiweb.net/shared/upload always fails with Bad Request.
I have reduced it to the smallest possible case and would like to know whether this is an
account eligibility issue or something I am doing wrong.

What happens

Filling the Share Add-on form and pressing Save shows “Bad Request”. Watching the network,
the request and response are:

POST https://ankiweb.net/svc/shared/upload-addon
Content-Type: application/octet-stream
→ HTTP 400, response body empty

The 400 has no message in it, so the page has nothing to display beyond “Bad Request”.

Minimal reproduction

A 537-byte add-on: a single __init__.py that adds one Tools menu entry, zipped with
__init__.py at the archive root, no __pycache__, no top-level folder. Form filled with
Title “Upload test”, Tags “test”, Support Page empty, Description one sentence, one branch
with a valid version range (25.09 → 26.99). Same 400.

The entire add-on is this one file, zipped as init.py at the archive root:

"""Minimal Anki add-on used to test whether AnkiWeb accepts an upload at all.

It registers one Tools-menu entry that shows a message box. Nothing else: no hooks into
reviewing, no files written, no network. If this uploads and the real add-on does not, the
problem is the package; if this fails too, the problem is not the package.
"""

from aqt import mw
from aqt.qt import QAction
from aqt.utils import showInfo


def _hello() -> None:
    showInfo("Upload test add-on is installed and running.")


action = QAction("Upload Test — say hello", mw)
action.triggered.connect(_hello)
mw.form.menuTools.addAction(action)

What I have already ruled out

  • Description length — reduced to one short sentence, same 400
  • Tags and Support Page — emptied, same 400
  • Title length — 11 characters, well under the 80 limit, same 400
  • The package — replaced with the 537-byte add-on above, same 400
  • manifest.json — tried with and without, same 400
  • Invalid version range — a reversed range gives a clear client-side “invalid version range”
    message instead, so the range in the failing attempts is valid
  • Session/auth — I am logged in, and other service endpoints return 200 for the same session
    (for example /svc/shared/list-mine and /svc/account/get-account-status)

The zip itself is a plain deflate archive, no ZIP64, no directory entries, no comment, and it
passes an integrity check.

My question

Is there an account requirement for uploading add-ons — a minimum account age, a verification step, or manual approval? I have seen other threads mention an “account is too new” message, but I never receive that message, only a bare 400.

Thanks.

See: