Skip to content

ImportError: cannot import name 'TypeAliasType' from 'typing_extensions'

Nothing left your machine, and nothing about OpenAI is involved. This is CPython’s import system reporting that a module loaded successfully but does not contain a name something asked it for. There is no HTTP status, no request id, no token spend, and no model — so it is not an authentication problem, not a quota problem, not a malformed request, and not the API changing under you. The vendor’s name appears in your command only because the SDK is the first thing in your program deep enough to touch a typing backport; the failure is in your environment’s package resolution.

Read the path, not the package name

The message has a second half that almost everyone skips: after the module name, Python prints the file it actually imported. That path is the diagnosis, and it answers a question the package name cannot.

typing_extensions is a backport. It exists to hand libraries symbols that newer interpreters have in the standard library, so that the same code runs on older ones. TypeAliasType is one of those symbols. An import of it fails for exactly one reason — the file Python loaded does not define it — and there are two very different ways that happens:

  • The installed release predates the symbol. The ordinary case. The path points into your environment’s site-packages, and a newer release is the fix.
  • The file Python loaded is not the package you think it is. A typing_extensions.py sitting in your working directory or on PYTHONPATH, a vendored copy inside another package, a stale .pyc left behind, a system-level install ahead of your virtual environment on sys.path. Here the path points somewhere unexpected, and upgrading the package changes nothing at all, forever, because the import never resolves to the thing you upgraded.

The second case is why “just upgrade it” fails permanently for a minority of people while working instantly for everyone else. One glance at the printed path tells you which group you are in, and it costs nothing.

If you want it explicitly, ask the interpreter that is failing — the same one, in the same environment, not a fresh shell:

import typing_extensions, sys
print(typing_extensions.__file__, sys.executable)

A __file__ outside your environment is the whole answer. A sys.executable you did not expect is the adjacent classic: pip and python resolving to different environments, so everything you installed went somewhere the failing process never looks.

Who actually asked for the symbol

The traceback’s last frame names typing_extensions, and its first frame names your import openai. Neither is the useful one. The frame in between names the package that demanded the new symbol, and that package is the one whose requirement sets your floor.

That matters because it tells you which constraint to fix. Modern data-modelling and validation layers reach for the newest typing constructs, and the SDK depends on them rather than on the backport directly. Chasing the requirement up one level turns “something wants a newer typing_extensions” into “this named package wants it”, which is a constraint you can actually write down.

It also disposes of a plausible non-fix: upgrading Python does not help. Libraries import these names from the backport unconditionally, precisely so they do not have to branch on interpreter version. A newer interpreter carrying the symbol in its own typing module is not consulted.

Is retrying useful?

No, and not in the weak sense — there is nothing here that could be retried.

The exception is raised while your module graph is being built. No request object exists, no client has been constructed, and no transport code has run. The SDK’s own retry policy — connection errors, 408, 409, 429 and 5xx responses, twice by default — operates on HTTP round trips, and none of it is reachable from here. If you have wrapped your API call in a retry decorator, that decorator is not even defined yet at the moment this fires.

Re-running the same interpreter against the same sys.path executes the same resolution and raises the same ImportError at the same line. The only thing in this story that can usefully be re-run is your installer, and re-running it with the same constraints and a warm cache reproduces the same resolution too — which is the trap covered in the next section.

The fix that works today and re-arms tomorrow

Upgrading the backport by hand clears the error immediately. It is also the version of this fix most likely to bring you back here, and the reason is worth understanding once.

An old release is usually installed because something asked for it — a dependency with an upper bound, a lockfile, or a resolver decision made to satisfy some other constraint. Upgrading it manually overrides that decision without changing the constraint that produced it. Your environment now works and pip considers it inconsistent, and the next thing that touches dependencies puts it back: a pip install of anything else, a reinstall from requirements, a fresh container build, a CI runner that starts from a clean cache.

The check that catches this takes one command:

pip check

A clean result means nothing is holding a conflicting requirement and your upgrade is stable. A reported conflict names the package that pinned you, and that package is where the real fix goes — upgrade it, or relax the bound deliberately and write down why.

There is a second tempting non-fix in the same family: pinning the OpenAI SDK back to an older release. It often works, because an older SDK carries a lower floor on the layers underneath it. You have then fixed a packaging problem by freezing an unrelated package, in a pin nobody will remember the reason for, and you have given up SDK changes you did want. If you must do it to ship today, pin with a comment naming this error.

Fix by what the path told you

  • Path is in your environment, release is simply old — upgrade the backport inside the environment the failing interpreter uses (python -m pip, not a bare pip), then run pip check before you believe it.
  • pip check names a package holding a bound — that package is the fix. Upgrading it usually lifts the floor for free; if it cannot be upgraded, the constraint is a real one and you need a different combination, not a manual override.
  • Path points outside site-packages — you have a shadowing file. Rename or delete it, clear stale bytecode, and check PYTHONPATH and your working directory. No amount of installing fixes this one.
  • sys.executable is not the environment you installed into — you have two environments. Install with python -m pip from the same interpreter that fails, which makes the mismatch impossible by construction.
  • Works locally, fails in a container or CI — the resolution differs because the cache differs. Reproduce with a clean build, not an incremental one, or you are testing your cache rather than your manifest.

How to confirm it’s fixed

Two steps, and the second is the one that matters.

First, in the environment that was failing, start a fresh interpreter and import the SDK. A long-running process, a notebook kernel, or a dev server started before the install still holds the old module in memory and will keep reporting success or failure that has nothing to do with the current state of disk.

Second, prove it survives a rebuild. Install from your lockfile or requirements into a brand-new virtual environment — or build the container image without the cache — and import again there. A fix that only exists in your current environment is not a fix, it is a local override with a delay fuse, and this step is the difference between the two. Finish with pip check in the new environment; a clean result is what tells you the constraint, and not just the symptom, was addressed.

  • ChatCompletionMessageToolCallParam “cannot instantiate typing.Union” is the call-site half of the same reframe: also a plain Python error with the vendor’s name attached by coincidence, but there the import succeeded and the bug is in how a type was used.
  • ERROR Invalid Version is the other shape of “a version string broke something you did not write” — useful when you need to work out which program produced a string and which one choked on it.
  • openai.error.APIConnectionError is the first failure you can meet after the import works, and it is the clearest contrast: that one has a transport layer and a retry policy, this one has neither.
  • The AI coding error triage tool sorts on the signals this page used: whether a status code exists, whether a request id exists, and whether anything ever left the process.