pallets/flask · error · NoAppException

Function reference must be a simple name

Error message

Function reference must be a simple name: {app_name!r}.

What it means

Raised by find_app_by_string when FLASK_APP parses as a call expression (ast.Call) but the function being called is not a bare name — e.g. it is an attribute access like pkg.mod.create_app or a subscript. The CLI only supports calling a simple top-level name in the module.

Solutions

  1. Reference a top-level name in the module: export FLASK_APP='module:create_app()'.
  2. Add a module-level wrapper that calls the nested factory.
  3. Import the factory into the target module's top level and reference it there.

Example fix

// before
# export FLASK_APP='app:myapp.factory()'  # raises
// after
# in app.py: from myapp import factory as create_app
# export FLASK_APP='app:create_app()'
Defensive patterns

Strategy: validation

Validate before calling

import ast
expr = ast.parse(app_name.strip(), mode='eval').body
if isinstance(expr, ast.Call) and not isinstance(expr.func, ast.Name):
    raise ValueError('FLASK_APP function reference must be a simple name')

Type guard

import ast
def is_simple_call(s) -> bool:
    expr = ast.parse(s.strip(), mode='eval').body
    return not (isinstance(expr, ast.Call) and not isinstance(expr.func, ast.Name))

Try / catch

try:
    app = find_app_by_string(module, app_name)
except NoAppException:
    # add a top-level wrapper and retry
    raise

Prevention

When it happens

Trigger: export FLASK_APP='module:pkg.create_app()' or FLASK_APP='module:obj["factory"]()' — function reference is an attribute/subscript, not a Name.

Common situations: Trying to invoke a factory nested under a submodule via dotted notation in FLASK_APP; refactoring that moved the factory into a sub-package.

Related errors


AI-assisted analysis of pallets/flask@3596b1ab61 (2026-08-11). Data as JSON: /api/errors/fe76c88aea23f13c. Report an issue: GitHub.

Appendix: source

Thrown at src/flask/cli.py:142

    from . import Flask

    # Parse app_name as a single expression to determine if it's a valid
    # attribute name or function call.
    try:
        expr = ast.parse(app_name.strip(), mode="eval").body
    except SyntaxError:
        raise NoAppException(
            f"Failed to parse {app_name!r} as an attribute name or function call."
        ) from None

    if isinstance(expr, ast.Name):
        name = expr.id
        args = []
        kwargs = {}
    elif isinstance(expr, ast.Call):
        # Ensure the function name is an attribute name only.
        if not isinstance(expr.func, ast.Name):
            raise NoAppException(
                f"Function reference must be a simple name: {app_name!r}."
            )

        name = expr.func.id

        # Parse the positional and keyword arguments as literals.
        try:
            args = [ast.literal_eval(arg) for arg in expr.args]
            kwargs = {
                kw.arg: ast.literal_eval(kw.value)
                for kw in expr.keywords
                if kw.arg is not None
            }
        except ValueError:
            # literal_eval gives cryptic error messages, show a generic
            # message with the full expression instead.
            raise NoAppException(
                f"Failed to parse arguments as literal values: {app_name!r}."

View on GitHub (pinned to 3596b1ab61)