Ask

Python says there is no module named tkinter, but tkinter is part of the standard library — how can it be missing?

The version-manager case deserves emphasis because it produces the most confusing version of this.

It is silent. You install a Python version, it succeeds, everything looks correct, and the only symptom appears later when you import one specific module. The same thing happens with a couple of other standard library modules that wrap system libraries — the compression and database ones are the usual companions.

So if tkinter is missing on a version-managed interpreter, check those too before you rebuild, and install all the development packages in one go. Otherwise you rebuild for tkinter today and rebuild again next week for something else.

Most of these version managers publish a list of the system packages to install first for exactly this reason. Reading it once saves several rebuilds.

26 · in/python-beginners ·

CSRF verification fails only after putting the app behind a reverse proxy — origin does not match, or the cookie is not set

Three separate checks are involved and they fail with different messages, which is why this feels inconsistent. Once you separate them the fix is mechanical.

Check one: the Host header. The framework compares the incoming host against the allowed hosts list and rejects anything else. That is the error you already fixed. It is unrelated to CSRF and it is why fixing it did not help.

Check two: the Origin or Referer header against the trusted origins list. This is your first error message. On an unsafe request the framework compares the browser-supplied origin against a configured list, and here is the part that catches everyone: the entries must include the scheme. A bare hostname does not match. You need the full https://host form, and if you also reach it on another name, that name needs its own entry.

Check three: the cookie. Your second error message means the browser did not send the CSRF cookie back, and there are three usual reasons:

  • The cookie is marked secure and you are on plain HTTP somewhere. If the setting for a secure CSRF cookie is on, the browser will only send it over HTTPS. Mixed access — HTTPS from outside, plain HTTP when you test internally — produces exactly this, intermittently, depending on how you happened to reach it.

  • The framework thinks the request is not secure. This is the big one for your deployment shape and the root of most of this. Your proxy terminates TLS and forwards plain HTTP to the application, so the application sees an insecure request. It then builds redirects as http://, decides differently about secure cookies, and disagrees with the browser about the origin.

    The fix is the setting that tells the framework to trust a forwarded protocol header, so it treats requests as secure when the proxy says they were. Only set this when a proxy you control is genuinely in front and is overwriting that header, because if a client can set it themselves you have handed them a way to make the framework believe an insecure request was secure.

    Your proxy must also actually send that header. Most do by default; confirm rather than assume.

  • The host in the cookie's domain does not match the host you are browsing. Usually from setting a cookie domain explicitly when you did not need to. If you have set one, try removing it.

The complete checklist for this deployment shape, which is what you asked for:

  1. Allowed hosts includes every hostname it is reached by.
  2. Trusted origins includes each of those with the scheme.
  3. The proxy protocol header setting is enabled, and the proxy sets that header.
  4. The proxy forwards the original Host header rather than rewriting it to the backend address.
  5. Secure cookie settings are on, and every path to the app is HTTPS.

Debugging tip that finds it fastest: log the incoming headers at the application for one request. You will see immediately whether the host is what you expect, whether the forwarded protocol header is present, and whether the cookie came back. Nearly every case of this is visible in one dump of the headers, and it beats changing settings one at a time.

30 · in/fullstack ·