How to Fix: error: error calling default export
Fixing the “error: error calling default export” Bug When Running Python Through a JavaScript/WebAssembly Runtime
This error usually means the host runtime is trying to call a default export from a generated module, but the loaded Python entrypoint does not expose what the JavaScript side expects. In practice, your Python code is often valid, but the integration layer between Python, WebAssembly, and the JavaScript loader is misaligned.
Given this test case:
def talk(message):
return "Talk " + message
def main():
print(talk("Hello World"))
return 0
if __name__ == "__main__":
main()
the Python itself is straightforward. The failure happens because the surrounding toolchain is attempting to execute the compiled or wrapped module through a default export contract that is missing, undefined, or incompatible.
Understanding the Root Cause
The message “error: error calling default export” typically appears in environments where Python is executed through a JavaScript-facing runtime such as a browser-based interpreter, a bundler-integrated WASM loader, or a server-side bridge that expects a module entry function.
There are a few common technical reasons:
- The runtime expects a default-exported function, but your generated module exports named functions or an object instead.
- The entrypoint is being invoked incorrectly. For example, the host may call
module.default()while the module actually exposesmain,run, or an initialization factory. - Python scripts are not always equivalent to JavaScript modules. A plain Python file with
if __name__ == "__main__"works when executed as a script, but not every embedding tool automatically maps that script behavior to a callable JavaScript default export. - Bundler or loader transformation issues can wrap the compiled output differently in development versus production, causing the default export to disappear.
- Async initialization is skipped. Some runtimes require awaiting module setup before calling exported functions. If initialization fails or is skipped, the default export call can throw a generic error.
In short, the bug is usually not in talk() or main(). It is in the integration boundary between the Python file and the code that tries to load and run it.
Step-by-Step Solution
The most reliable fix is to make sure your runtime and your entry file agree on how execution starts.
1. Verify whether your runtime expects a script or a module
If the tool is designed to run a Python script directly, use a script entrypoint and do not depend on a JavaScript-style default export assumption.
def talk(message):
return "Talk " + message
def main():
print(talk("Hello World"))
return 0
if __name__ == "__main__":
raise SystemExit(main())
Using raise SystemExit(main()) is often cleaner in embedded runtimes because it makes the exit code explicit.
2. Check the JavaScript loader code
If the host environment is doing something like this, it may be wrong:
const mod = await loadPythonModule("./main.py");
await mod.default();
If your runtime does not actually expose a default export, switch to the correct API. Depending on the platform, the right pattern may look more like this:
const mod = await loadPythonModule("./main.py");
await mod.run();
or:
const runtime = await initializeRuntime();
await runtime.exec("./main.py");
or:
const mod = await loadPythonModule("./main.py");
await mod.main();
The exact method name depends on the toolchain, but the key fix is the same: do not call default unless the module really exports default.
3. If the tool supports explicit exports, expose the expected entrypoint
Some Python-to-WASM or Python embedding systems allow explicit registration of callable functions. In that case, export or register main instead of relying on script execution side effects.
def talk(message):
return "Talk " + message
def main():
return talk("Hello World")
Then call that registered function from the host runtime and print the result on the JavaScript side if needed.
const mod = await loadPythonModule("./main.py");
console.log(await mod.main());
4. Confirm ESM/CommonJS compatibility
If your build pipeline uses ES modules, a mismatch between ESM and CommonJS can surface as a default export error. For example, this is a common source of bugs:
import mod from "./generated-module.js";
await mod();
when the actual output is:
export function main() {
// ...
}
Use the correct import form:
import * as mod from "./generated-module.js";
await mod.main();
or:
import { main } from "./generated-module.js";
await main();
5. Make initialization explicit
Many runtimes require async startup before calling any exported API. If initialization is skipped, the default export call may fail even though the module file exists.
const runtime = await initializeRuntime();
const mod = await runtime.loadModule("./main.py");
await mod.main();
If your platform has a documented bootstrapping sequence, follow that exactly. Refer to the project documentation or issue tracker rather than assuming browser-native module semantics.
6. Use a minimal sanity test
Before debugging your real app, verify the runtime can load a trivial function and call it directly.
def hello():
return "Hello World"
Then invoke only that function from the host environment. If that works, the problem is likely with the chosen entrypoint pattern rather than Python execution itself.
7. Prefer returning values over printing during integration tests
When debugging cross-runtime issues, returning data is easier to validate than relying on stdout.
def talk(message):
return "Talk " + message
def main():
return talk("Hello World")
if __name__ == "__main__":
print(main())
raise SystemExit(0)
This gives you two ways to validate behavior: direct script execution and direct function invocation.
Common Edge Cases
- Default export exists but is not a function: The loader may return an object, configuration wrapper, or promise instead of a callable.
- Async function not awaited: If the runtime returns a promise and the caller invokes it incorrectly, you may see a generic export error.
- Wrong file type in the bundler: A Python file may be treated as a static asset instead of an executable module.
- Path resolution problems: The module loads from the wrong location, leading to an unexpected wrapper or empty module object.
- Production build differences: Development servers may auto-wrap modules in a way that hides export mismatches until deployment.
- Name collision with main: Some frameworks reserve entry names like
mainor generate wrappers around them. - stdout not wired: Your function runs, but output never appears, making it look like execution failed.
- Python script semantics vs embedded module semantics:
__name__ == "__main__"may never trigger if the file is imported rather than executed as a script.
FAQ
Why does the Python script work locally but fail with “error calling default export” in the app?
Because local Python execution runs the file as a script, while the app likely loads it through a module bridge that expects a JavaScript-compatible default export or a specific runtime API.
Should I remove the if __name__ == "__main__": block?
Not necessarily. Keep it if you want script-style execution, but also expose a callable function like main() for the host runtime. That gives you compatibility with both direct execution and embedded invocation.
How do I know whether to call default, main, or run?
Inspect the actual module shape produced by your toolchain and follow the runtime documentation. The fix is to call the real exported entrypoint, not to assume the module behaves like a standard JavaScript default export.
The durable solution is simple: treat the bug as an entrypoint contract mismatch. Make your Python code expose a clear callable function, initialize the runtime correctly, and update the host loader to call the actual exported API instead of blindly invoking a default export.