Your FastAPI application is failing because the allow_origins parameter in your CORS configuration isn’t formatted as a Python list.

Here’s a breakdown of the common culprits and how to fix them:

1. allow_origins is a String Instead of a List

This is the most frequent offender. You’ve likely defined your allowed origins as a single string, like "http://localhost:3000", instead of a list containing that string.

Diagnosis: Inspect your CORSMiddleware instantiation. Look for the allow_origins argument.

Fix: Wrap your origin string(s) in square brackets [].

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [
    "http://localhost:3000",
    "https://your-frontend-domain.com",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,  # <-- This should be a list
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Why it works: FastAPI’s CORSMiddleware strictly expects allow_origins to be an iterable (like a list or tuple) of strings, where each string is a valid origin. A single string is not considered iterable in this context.

2. allow_origins is a Tuple Instead of a List (Less Common, but still an issue)

While tuples are also iterables, allow_origins is typically expected to be a list. While FastAPI might sometimes handle a tuple, it’s best practice and safer to use a list to avoid subtle compatibility issues.

Diagnosis: Similar to the first point, check the type of allow_origins.

Fix: Convert your tuple to a list.

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# If origins was defined as a tuple:
# origins = ("http://localhost:3000",)
origins = ["http://localhost:3000"] # Convert to list

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins, # Ensure it's a list
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Why it works: Using a list adheres to the explicit type hint and common usage pattern for allow_origins, ensuring predictable behavior.

3. allow_origins is a Set Instead of a List

Sets are iterables and unique, which might seem logical for origins. However, CORSMiddleware specifically wants a list.

Diagnosis: Check the allow_origins argument’s type.

Fix: Convert your set to a list.

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# If origins was defined as a set:
# origins = {"http://localhost:3000", "https://another-domain.com"}
origins = list({"http://localhost:3000", "https://another-domain.com"}) # Convert to list

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins, # Ensure it's a list
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Why it works: Explicitly converting to a list satisfies the expected data structure for allow_origins, guaranteeing compatibility.

4. Misunderstanding allow_origins for allow_origin_regex

You might be trying to use a regular expression for origins but are passing it to allow_origins instead of allow_origin_regex.

Diagnosis: Review your CORSMiddleware configuration. If allow_origins contains a string that looks like a regex (e.g., r"http://.*"), this is likely the issue.

Fix: Use allow_origin_regex for patterns and ensure allow_origins is a list of exact matches if you need both.

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# For specific origins
exact_origins = [
    "http://localhost:3000",
]

# For origins matching a pattern
origin_regexes = [
    r"https://\w+\.your-frontend-domain\.com", # Example regex
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=exact_origins, # List of exact origins
    allow_origin_regex=origin_regexes, # List of regex patterns
    allow_credentials=True,
    allow_methods=["GET", "POST"],
    allow_headers=["Authorization"],
)

Why it works: allow_origins is for exact origin matching, while allow_origin_regex is designed to match origins using regular expressions. Using the correct parameter ensures your origin validation works as intended.

5. allow_origins is None or Not Provided

While the error message specifically states it must be a list, sometimes a configuration error might lead to allow_origins being None or entirely absent, which the middleware might then try to interpret as an empty list or fail with a similar type error.

Diagnosis: Check if allow_origins is explicitly set or if it’s being conditionally included.

Fix: Always explicitly define allow_origins as a list, even if it’s empty for development or testing.

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# If you want to allow all origins (use with extreme caution in production)
# all_origins = ["*"]

# If you want to allow no origins (effectively disabling CORS for incoming requests)
no_origins = []

app.add_middleware(
    CORSMiddleware,
    allow_origins=no_origins, # Explicitly set, even if empty
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Why it works: Explicitly providing an empty list [] for allow_origins satisfies the type requirement and correctly configures the middleware to not allow any origins, which is a valid (though often not desired) CORS setup.

After resolving this, you’ll likely encounter errors related to allow_methods or allow_headers not being correctly configured if they were also part of the same initial misconfiguration.

Want structured learning?

Take the full Fastapi course →