If you’ve ever tried packaging a Python project using cx_Freeze and suddenly faced this dreaded message:
Python error in main script
Runtime error
trust me, you’re not alone. When I first ran into it, I was scratching my head for hours. After digging in, I realized the error wasn’t in my main game logic it was in the way I set up cx_Freeze. Let me walk you through my exact mistake, the fix, and how I turned this into a small learning project.
The Code That Caused the Error
Here’s the original setup.py
I wrote:
import sys
from cx_Freeze import setup, Executable
base = None
if sys.platform == "win32":
base = "win32GUI" # <-- I thought this was correct
setup(
name="application",
version="0.1",
description="app",
executables=[Executable("TICTACTOE.py", base=base)]
)
And here’s my main script (TICTACTOE.py
), which is just a console-based Tic Tac Toe game:
import copy as c
import sys
def printBoard(arg):
i = 0
for v in arg.keys():
i += 1
if i % 3 == 0 and i < 9:
print(arg[v], '\n- + - + -')
elif i == 9:
print(arg[v])
else:
print(arg[v], '', '|', end=' ')
def check(b, arg):
def plagfn(b):
global looper
looper = False
plag = input('Play again? y/n ')
if plag == 'Y':
theBoard = c.copy(newBoard)
else:
sys.exit()
val = list(b.values())
l = [''] * 9
u = [''] * 9
d = [''] * 9
for i in [0, 3, 6]:
l[i] = (val[i] == val[i+1] == val[i+2] == arg)
for i in range(3):
u[i] = (val[i] == val[i+3] == val[i+6] == arg)
for i in [0, 2]:
d[i] = (val[i] == val[4] == val[8-i] == arg)
if ('' not in b.values()):
print('Its draw !')
plagfn(b)
if (True in l) or (True in u) or (True in d):
print(arg, 'is a winner !')
plagfn(b)
while True:
theBoard = {'TL': '', 'TM': '', 'TR': '',
'ML': '', 'MM': '', 'MR': '',
'LL': '', 'LM': '', 'LR': ''}
sample = {k: k for k in theBoard.keys()}
newBoard = c.copy(theBoard)
print('The viable inputs are \n')
printBoard(sample)
print('\nStart')
printBoard(theBoard)
looper = True
i = 0
while looper:
i += 1
arg = 'O' if i % 2 == 0 else 'X'
v = input('\nYour turn ' + str(arg) + '! \n')
while v not in list(theBoard.keys()):
print('The viable inputs are \n')
printBoard(sample)
v = input('\nYour turn ' + str(arg) + '! \n')
while theBoard[v]:
print('Already played.')
v = input('Your turn ' + str(arg) + '! \n')
theBoard[v] = arg
printBoard(theBoard)
check(theBoard, arg)
The Error Explain
The real problem was here:
if sys.platform == "win32":
base = "win32GUI"
When I used "win32GUI"
, cx_Freeze built a windowed application, not a console one.
- A GUI app has no console, which means functions like
print()
andinput()
simply don’t work. - My Tic Tac Toe game depends heavily on
input()
. - Every time the code tried to read user input, it threw an
EOFError
, and cx_Freeze displayed it as “python error in main script … runtime error”.
In short: I told cx_Freeze to make a GUI app even though I only had a console app.
The Fix
The fix is very simple. I just needed to build my program as a console app, not a GUI app.
import sys
from cx_Freeze import setup, Executable
base = None
# Keep base=None for console programs.
# Only use "Win32GUI" for GUI frameworks like tkinter or PyQt.
setup(
name="application",
version="0.1",
description="app",
executables=[Executable("TICTACTOE.py", base=base)] # Console build
)
After that, the .exe
launched with a console window, and my game worked perfectly.
Adding More Practice Functionality
Since this was a learning project, I took the opportunity to add a couple of new features.
Score Tracking Across Games
Instead of exiting immediately when someone won, I added a scoreboard:
scores = {"X": 0, "O": 0, "Draw": 0}
Every time someone wins (or it’s a draw), I update the score and show the players their results so far.
Replay Without Restarting the Program
Originally, the game exited completely after a win or draw.
I modified the replay logic so players can decide whether to continue:
def plagfn(b, result):
global looper
looper = False
scores[result] += 1
print("Scoreboard:", scores)
plag = input('Play again? y/n ')
if plag.lower() == 'y':
return True
else:
sys.exit()
Now the game feels more like a mini tournament rather than a single match.
Final Thought
This debugging journey reminded me of two simple but powerful lessons: always match your app type with the correct cx_Freeze base use base=None
for console apps and base="Win32GUI"
for GUI frameworks like tkinter or PyQt and don’t just stop at fixing errors. Bugs can be opportunities to grow; by adding score tracking and replay loops, I turned a frustrating runtime issue into a chance to improve my game and sharpen my Python skills.