Say you add a picture to a Tkinter window and run the program. Python stops with this:

 File "bug.py", line 9, in <module> tk.Label(second, image=logo).pack() _tkinter.TclError: image "pyimage1" doesn't exist 

The message is confusing. You never typed the name pyimage1. Tkinter picked it when it created your PhotoImage. Below are the three causes of this exact error, plus one related error, each with a fix. I reproduced and tested every example with Python 3.14.

What the Error Means

When you create a PhotoImage, Tkinter hands it to Tk and names it something like pyimage1. The error means you asked Tk for an image with that name, and Tk doesn't have one. Either the image belongs to a different window, or it got deleted. Ask yourself three questions:

  1. Am I making more than one tk.Tk() window? That's Cause 1. 2. Am I destroying the main window and then opening a new one? That's Cause 2. 3. Is my PhotoImage sitting in a local variable inside a function? That's Cause 3.

Cause 1: More Than One tk.Tk()

import tkinter as tk first = tk.Tk() second = tk.Tk() # a second root window logo = tk.PhotoImage(file="icon.png") # created for the first root tk.Label(second, image=logo).pack() # used in the second root: TclError second.mainloop() 

Each tk.Tk() starts its own Tk interpreter, and an image belongs to just one of them. If you don't say which window an image is for, it goes to the first one you made. Here logo belongs to first. The label lives in second, and second can't see it.

Use exactly one tk.Tk() in your whole program. Every other window should be a tk.Toplevel. It runs inside the main window’s interpreter, so images are shared:

import tkinter as tk root = tk.Tk() second = tk.Toplevel(root) # an extra window that shares the same interpreter logo = tk.PhotoImage(file="icon.png") tk.Label(second, image=logo).pack() root.mainloop() 

Cause 2: The Image Belonged to a Window That Was Destroyed

import tkinter as tk root = tk.Tk() logo = tk.PhotoImage(file="icon.png") # created for the first root root.destroy() root2 = tk.Tk() # a new root tk.Label(root2, image=logo).pack() # the old image no longer exists: TclError root2.mainloop() 

The image was made for the first root window. Destroy that window and its images go with it. The new root can't use the old image, even though the Python variable logo is still there. You'll see this in programs that close a login window and then open the main window as a second tk.Tk().

Cause 1’s fix works best here too. Keep a single root, and hide or swap its contents. Stuck with a second root? Make the image after that root exists, and pass master so Tk knows who owns it:

import tkinter as tk root = tk.Tk() root.destroy() root2 = tk.Tk() logo = tk.PhotoImage(file="icon.png", master=root2) tk.Label(root2, image=logo).pack() root2.mainloop() 

Cause 3: Nothing Kept the Image Alive

import tkinter as tk root = tk.Tk() def show(): logo = tk.PhotoImage(file="icon.png") label = tk.Label(root, image=logo) label.pack() return label label = show() root.update() print("images Tk still has:", root.tk.call("image", "names")) # no pyimage1 in this list label.configure(image=label.cget("image")) # uses the deleted image: TclError root.mainloop() 

logo is a local variable. When show() returns, Python throws the PhotoImage away and Tk deletes the image. The label still points at the name pyimage1, so using it again fails. Does your picture just not show up, with no error? Check this first.

I printed the images Tk still had at that point. Yours is gone. Only Tk’s four built-in icons are left:

images Tk still has: ('::tk::icons::information', '::tk::icons::error', '::tk::icons::warning', '::tk::icons::question') 

Give the image something to hang onto. Store it on the widget itself, and it lives as long as the widget does:

import tkinter as tk root = tk.Tk() def show(): logo = tk.PhotoImage(file="icon.png") label = tk.Label(root, image=logo) label.image = logo # the reference that keeps the image alive label.pack() return label label = show() root.update() print("images Tk still has:", root.tk.call("image", "names")) # pyimage1 is in this list label.configure(image=label.cget("image")) root.mainloop() 

Now the reference holds it. pyimage1 stays in the list and nothing breaks:

images Tk still has: ('pyimage1', '::tk::icons::information', '::tk::icons::error', '::tk::icons::warning', '::tk::icons::question') 

A Debugging Trick: Ask Tk Which Images Exist

Don't guess. Ask Tk. This one line prints every image the interpreter holds right now, so you can see whether yours survived:

print(root.tk.call("image", "names")) 

If your pyimageN isn't in the list, the image was deleted (Cause 2 or 3). If it is in the list but the error still says it doesn't exist, the widget sits in a different window (Cause 1).

A Related Error: Too Early to Create Image

import tkinter as tk logo = tk.PhotoImage(file="icon.png") # RuntimeError: no default root window yet window = tk.Tk() tk.Label(window, image=logo).pack() window.mainloop() 

This one has its own message.

RuntimeError: Too early to create image: no default root window 

An image needs a window to live in, and Tkinter won't make one without it. Window first, image second:

import tkinter as tk window = tk.Tk() logo = tk.PhotoImage(file="icon.png") tk.Label(window, image=logo).pack() window.mainloop() 

Which Cause Is It?

What you see Cause Fix
image "pyimage1" doesn't exist, and the code has two tk.Tk() Cause 1 One tk.Tk(), extra windows as tk.Toplevel
The error appears after you close one window and open another Cause 2 Reuse one root, or create the image after the new root with master=
The image is created inside a function, or the picture just does not show Cause 3 Keep a reference: label.image = logo
Too early to create image Related Create the window before the image

The Rule, Stated Once

A PhotoImage belongs to one window’s interpreter. It lives only while Python holds a reference to it. So use a single tk.Tk(), create images after it, and keep each image in a variable that lasts as long as the widget.

Does your window freeze instead? See Why Your Tkinter App Freezes (Not Responding) and How to Fix It. If you want to learn Tkinter from a first window to full projects, start with Tkinter in Python, and if Python itself is new to you, Python for Beginners. Here's another error that looks like a missing-attribute mystery: PySerial: module ‘serial’ has no attribute ‘Serial’.

Download the code: the broken and fixed versions of all four are on GitHub, in Python-projects/Troubleshooting/tkinter-image-doesnt-exist. Open each one from inside its own folder, since it reads icon.png from wherever you run it.

Originally published on my blog. I post new C, Python and AI-agent guides there regularly.