I created a UI using Qt Designer and placed it in
src/main/resources/base/mainwindow.ui. Everything works withfbs run, but when I usefbs freezeand try to run the frozen app, I get aFileNotFoundError: [Errno 2] No such file or directory: 'mainwindow.ui'. How do I fix this?
When you're developing a PyQt5 application with fbs and loading .ui files at runtime, you'll often find that everything works perfectly during development (fbs run) but falls apart as soon as you freeze the application. The error looks something like this:
FileNotFoundError: [Errno 2] No such file or directory: 'mainwindow.ui'
[61742] Failed to execute script main
This is a common stumbling block, and the cause is straightforward once you understand how file paths change when an application is frozen.
Why This Happens
When you load your .ui file with a relative path like this:
qtCreatorFile = "mainwindow.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
Python resolves that relative path based on the current working directory — the folder from which the program is executed. During development, fbs run sets things up so that your working directory matches your project structure, and the file is found without trouble.
But after freezing, the frozen executable lives in a different location (target/), and the working directory when a user launches it could be almost anything. The relative path "mainwindow.ui" no longer points to the right place, and Python can't find the file.
The Fix: Use the fbs Application Context
The fbs framework provides a built-in way to locate resource files regardless of whether you're running in development or from a frozen build. That's what ApplicationContext.get_resource() is for.
If your .ui file is located at:
src/main/resources/base/mainwindow.ui
Then you can get the correct absolute path to it like this:
from fbs_runtime.application_context import ApplicationContext
appctxt = ApplicationContext()
ui_path = appctxt.get_resource("mainwindow.ui")
The get_resource() method returns the full, absolute path to the file — whether you're running with fbs run or from a frozen executable. This is the recommended approach when using fbs.
Here's a complete working example:
import sys
from PyQt5.QtWidgets import QMainWindow
from PyQt5 import uic
from fbs_runtime.application_context import ApplicationContext
class AppContext(ApplicationContext):
def run(self):
ui_path = self.get_resource("mainwindow.ui")
Ui_MainWindow, QtBaseClass = uic.loadUiType(ui_path)
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.window = MainWindow()
self.window.show()
return self.app.exec_()
if __name__ == "__main__":
appctxt = AppContext()
exit_code = appctxt.run()
sys.exit(exit_code)
Notice that uic.loadUiType() is called inside the run() method, after the application context is available. This ensures the resource path is resolved correctly before the .ui file is loaded.
An Alternative: Build an Absolute Path Yourself
If for some reason you don't want to use the application context to locate the file, you can construct an absolute path manually using sys.argv[0]. This points to the script (or frozen executable) that was launched, so you can use it to find files that sit alongside it:
import os
import sys
from PyQt5 import uic
qtCreatorFile = os.path.join(
os.path.abspath(os.path.dirname(sys.argv[0])),
"mainwindow.ui"
)
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
This builds a full path by combining the directory of the running script with the filename. It works in both development and frozen environments, as long as the .ui file ends up in the same folder as the executable after freezing.
That said, using get_resource() is still the better option with fbs, because fbs already handles the details of where resource files end up during freezing. You don't have to think about it.
A Note on the Original Code
The original code also had this block:
if __name__ == '__main__':
appctxt = AppContext()
stylesheet = appctxt.get_resource('mainwindow.ui')
appctxt.app.setStyleSheet(open(stylesheet).read())
exit_code = appctxt.run()
sys.exit(exit_code)
Here, get_resource('mainwindow.ui') is being used to load the .ui file as a stylesheet, which isn't correct. A .ui file is an XML file that describes widget layout — it's not a Qt stylesheet (.qss). Loading it with setStyleSheet() won't produce an error, but it also won't do anything useful. If you have a separate .qss stylesheet, load that with setStyleSheet(). Load the .ui file with uic.loadUiType() as shown above.
Summary
When packaging a PyQt5 app with fbs, any file you reference at runtime needs to be located using an absolute path. Relative paths work during development but fail after freezing because the working directory changes.
The simplest and most reliable fix is to use appctxt.get_resource("mainwindow.ui") to get the full path to your .ui file, and then pass that path to uic.loadUiType(). This works consistently in both development and production.
Create GUI Applications with Python & Qt6 by Martin Fitzpatrick
(PyQt6 Edition) The hands-on guide to making apps with Python — Over 15,000 copies sold!