4.0 crashes randomly when rendering animation in Cycles

I’m having a crashing issue where my Blender crashes randomly while rendering a 1080p 1356 frame animation with default light path settings, no motion blur and 128 samples in cycles with OpenImage Denoising. There are about 2.5M triangles in total, but I don’t see how that could be an issue, as I can render maybe 50-100 frames before Blender just closes. There are many Blenderkit assets in the scene so that might be a problem, but to not use them would mean an empty scene.

I cannot supply the project file as it contains paid assets.

I’m running on a 7950X3D (16C/32T), an RTX 4090 (24GB VRAM) with 64GB of DDR5 RAM, and the scene at most uses 7.3GB of VRAM, and 3.7GB of RAM at peak. While rendering, Blender as a whole uses 16GB of RAM.

I have no idea how Blender manages to crash despite my specs. I’ve tried disabling all third party addons to no avail and I have the most recent Nvidia Studio Drivers.

Here’s my crash log. I’ve tried reading through it but I don’t really know what to look for.

Previous crash log:
Pastebin link as it is WAY too long - https://pastebin.com/ixWtExEJ

New crash log:

# Blender 4.0.0, Commit date: 2023-11-13 17:26, Hash 878f71061b8e
bpy.context.scene.frame_start = 269  # Property
bpy.context.scene.frame_start = 268  # Property
Saved "MFF 2023.blend"  # Info
bpy.ops.outliner.item_activate(deselect_all=True)  # Operator
bpy.ops.outliner.item_activate(deselect_all=True)  # Operator
bpy.context.object.hide_viewport = False  # Property
bpy.context.object.hide_render = False  # Property
bpy.context.object.hide_render = True  # Property
bpy.context.object.hide_viewport = True  # Property
bpy.data.scenes["Scene"].(null) = True  # Property
bpy.context.space_data.context = 'RENDER'  # Property
Saved "MFF 2023.blend"  # Info

# backtrace
Exception Record:

ExceptionCode         : EXCEPTION_ACCESS_VIOLATION
Exception Address     : 0x00007FF72D9F232F
Exception Module      : blender.exe
Exception Flags       : 0x00000000
Exception Parameters  : 0x2
	Parameters[0] : 0x0000000000000000
	Parameters[1] : 0x0000000000000014


Stack trace:
blender.exe         :0x00007FF72D9F232F  Symbols not available


Loaded Modules :
0x00007FF72D880000 4.0.0.0              blender.exe
0x00007FF8FAA30000 10.0.19041.3570      ntdll.dll  
0x00007FF8FA4A0000 10.0.19041.3570      KERNEL32.DLL  
0x00007FF8F8500000 10.0.19041.3570      KERNELBASE.dll  
0x00007FF8F9460000 10.0.19041.3570      USER32.dll  
0x00007FF8F8800000 10.0.19041.3570      win32u.dll  
0x00007FF8FA470000 10.0.19041.3570      GDI32.dll  
0x00007FF8EEC70000                      tbb.dll  
0x00007FF8C0D20000                      tbbmalloc.dll  
0x00007FF8F88D0000 10.0.19041.3570      gdi32full.dll  
0x00007FF8F8830000 10.0.19041.3570      msvcp_win.dll  
0x00007FF8F8160000 10.0.19041.3570      ucrtbase.dll  
0x00007FF8FA290000 10.0.19041.3570      ADVAPI32.dll  
0x00007FF8F9DB0000 7.0.19041.3570       msvcrt.dll  
0x00007FF8FA7A0000 10.0.19041.3570      sechost.dll  
0x00007FF8F92B0000 10.0.19041.3570      RPCRT4.dll  
0x00007FF8F8A90000 10.0.19041.3570      SHELL32.dll  
0x00007FF8FA340000 10.0.19041.3570      ole32.dll  
0x00007FF8B9440000 14.29.30139.0        MSVCP140.dll  
0x00007FF8EF990000 10.0.19041.3570      VERSION.dll  
0x00007FF8F9E60000 10.0.19041.3570      combase.dll  
0x00007FF8EF8E0000 14.29.30139.0        VCRUNTIME140.dll  
0x00007FF8FA1D0000 10.0.19041.3570      SHLWAPI.dll  
0x00007FF8EF9A0000 14.29.30139.0        VCRUNTIME140_1.dll  
0x00007FF8F8110000 10.0.19041.3570      CFGMGR32.dll  
0x00007FF8FA560000 10.0.19041.3570      WS2_32.dll  
0x00007FF8F9CE0000 10.0.19041.3570      OLEAUT32.dll  
0x00007FF8EECE0000 10.0.19041.3570      dbghelp.dll  
0x00007FF8FA6F0000 10.0.19041.3570      shcore.dll  
0x00007FF8F9BD0000 10.0.19041.3570      IMM32.dll  
0x00007FF861A20000 4.1.0.0              embree4.dll  
0x00007FF8A6D00000 6.1.0.0              sycl6.dll  
0x00007FF8B91F0000                      OpenImageIO_Util.dll  
0x00007FF871630000                      OpenImageIO.dll  
0x00007FF8BBC20000                      boost_python310-vc142-mt-x64-1_80.dll  
0x00007FF85B500000                      cycles_kernel_oneapi_aot.dll  
0x00007FF86D760000                      OpenColorIO_2_2.dll  
0x00007FF8B3FE0000                      MaterialXCore.dll  
0x00007FF8B9FB0000                      MaterialXFormat.dll  
0x00007FF8B7310000                      epoxy-0.dll  
0x00007FF8B93F0000                      Iex.dll  
0x00007FF8724C0000                      OpenEXR.dll  
0x00007FF8B8EC0000                      Imath.dll  
0x00007FF8582B0000 10.0.0.0             openvdb.dll  
0x00007FF872010000 60.3.100.0           avformat-60.dll  
0x00007FF829F40000 60.3.100.0           avcodec-60.dll  
0x00007FF8C31D0000 60.1.100.0           avdevice-60.dll  
0x00007FF871470000 58.2.100.0           avutil-58.dll  
0x00007FF8B8DC0000 7.1.100.0            swscale-7.dll  
0x00007FF8F8A60000 10.0.19041.3570      bcrypt.dll  
0x00007FF86E1C0000                      fftw3f.dll  
0x00007FF859A60000                      usd_ms.dll  
0x00007FF86CF70000 1.2.2.0              sndfile.dll  
0x00007FF86CE30000 1.21.1.0             OpenAL32.dll  
0x00007FF8BFE20000                      boost_thread-vc142-mt-x64-1_80.dll  
0x00007FF86CC90000 2.28.2.0             SDL2.dll  
0x00007FF8B5D10000                      boost_locale-vc142-mt-x64-1_80.dll  
0x00007FF8F9760000 10.0.19041.3570      SETUPAPI.dll  
0x00007FF86C6A0000                      gmp-10.dll  
0x00007FF8F69B0000 10.0.19041.3570      dxgi.dll  
0x00007FF8EB880000                      tbbmalloc_proxy.dll  
0x00007FF8B9350000 10.0.19041.1         AVIFIL32.dll  
0x00007FF86C7C0000 3.10.13150.1013      python310.dll  
0x00007FF8E8B20000 6.10.19041.3570      COMCTL32.dll  
0x00007FF8F5CE0000 10.0.19041.3570      dwmapi.dll  
0x00007FF86C5B0000                      fftw3.dll  
0x00007FF8DF780000                      libgmpxx.dll  
0x00007FF8EEFD0000 10.0.19041.3570      dbgeng.dll  
0x00007FF8A8330000                      OpenEXRCore.dll  
0x00007FF8CBC20000                      IlmThread.dll  
0x00007FF8B91D0000 4.10.100.0           swresample-4.dll  
0x00007FF8E02A0000 10.0.19041.3570      Secur32.dll  
0x00007FF8B8EA0000 10.0.19041.1         AVICAP32.dll  
0x00007FF886200000                      MaterialXRender.dll  
0x00007FF877F60000 10.0.19041.3570      OPENGL32.dll  
0x00007FF872C90000                      MaterialXGenGlsl.dll  
0x00007FF871F50000                      MaterialXGenShader.dll  
0x00007FF8ED5B0000 10.0.19041.3570      WINMM.dll  
0x00007FF84FE50000 10.0.19041.1         MSACM32.dll  
0x00007FF8B8C00000 10.0.19041.1         MSVFW32.dll  
0x00007FF8EEED0000 10.0.19041.3570      dbgmodel.dll  
0x00007FF8EEF90000 10.0.19041.3570      XmlLite.dll  
0x00007FF877880000 10.0.19041.3570      GLU32.dll  
0x00007FF8E0710000 10.0.19041.1         winmmbase.dll  
0x00007FF8F7FF0000 10.0.19041.3570      SSPICLI.DLL  
0x00007FF8F5FD0000 10.0.19041.3570      kernel.appcore.dll  
0x00007FF8F61D0000 10.0.19041.3570      windows.storage.dll  
0x00007FF8F7B50000 10.0.19041.3570      Wldp.dll  
0x00007FF8F5A10000 10.0.19041.3570      uxtheme.dll  
0x000001F833F00000 10.0.19041.3570      bcryptPrimitives.dll  
0x00007FF8F8040000 10.0.19041.3570      profapi.dll  
0x00007FF8F9690000 2001.12.10941.16384  clbcatq.dll  
0x00007FF8F07E0000 10.0.19041.3570      MMDevApi.dll  
0x00007FF8F7EA0000 10.0.19041.3570      DEVOBJ.dll  
0x00007FF8F0870000 10.0.19041.3570      AUDIOSES.DLL  
0x00007FF8F7670000 10.0.19041.3570      powrprof.dll  
0x00007FF8F7530000                      UMPDC.dll  
0x00007FF8FA5D0000 10.0.19041.3570      MSCTF.dll  
0x00007FF8F3A70000 7.0.19041.3570       PROPSYS.dll  
0x00007FF8F1BB0000 10.0.19041.3570      AppXDeploymentClient.dll  
0x00007FF873830000 31.0.15.4601         nvoglv64.dll  
0x00007FF8F29C0000 10.0.19041.3570      WTSAPI32.dll  
0x00007FF8F7CE0000 10.0.19041.3570      msasn1.dll  
0x00007FF8EF950000 10.0.19041.3570      cryptnet.dll  
0x00007FF8F82F0000 10.0.19041.3570      CRYPT32.dll  
0x00007FF8EF730000 10.0.19041.3570      drvstore.dll  
0x00007FF8F7AC0000 10.0.19041.3570      cryptbase.dll  
0x00007FF8F89F0000 10.0.19041.3570      wintrust.dll  
0x00007FF8F9740000 10.0.19041.3570      imagehlp.dll  
0x00007FF8F7AA0000 10.0.19041.3570      CRYPTSP.dll  
0x00007FF8F7150000 10.0.19041.3570      rsaenh.dll  
0x00007FF8F6980000 10.0.19041.3570      gpapi.dll  
0x00007FF8E58E0000 31.0.15.4601         nvgpucomp64.dll  
0x00007FF8F7270000 10.0.19041.3570      ntmarta.dll  
0x00007FF8E8260000 10.0.19041.3570      dxcore.dll  
0x00007FF8F6DE0000 10.0.19041.3570      WINSTA.dll  
0x00007FF8C3EE0000 10.0.19041.3570      dataexchange.dll  
0x00007FF8F4010000 10.0.19041.3570      d3d11.dll  
0x00007FF8F4E00000 10.0.19041.3570      dcomp.dll  
0x00007FF8F0A40000 10.0.19041.3570      twinapi.appcore.dll  
0x00007FF8D8390000 10.0.19041.3570      textinputframework.dll  
0x00007FF8F5370000 10.0.19041.3570      CoreUIComponents.dll  
0x00007FF8F56D0000 10.0.19041.3570      CoreMessaging.dll  
0x00007FF8F4CA0000 10.0.19041.3570      wintypes.dll  
0x00007FF8C35B0000 10.0.19041.3570      explorerframe.dll  
0x00007FF8C45F0000 10.0.19041.3570      directmanipulation.dll  
0x00007FF8F3B70000 10.0.19041.3570      policymanager.dll  
0x00007FF8F71E0000 10.0.19041.3570      msvcp110_win.dll  
0x00007FF8F93E0000 10.0.19041.3570      coml2.dll  
0x00007FF8C1370000 10.0.19041.3570      LINKINFO.dll  
0x00007FF8F5910000 10.0.19041.3570      apphelp.dll  
0x00007FF8B8A80000 10.0.19041.3570      zipfldr.dll  
0x00007FF8E0030000 10.0.19041.3570      Windows.StateRepositoryPS.dll  
0x000001F8346E0000 3.10.13150.1013      python3.DLL  
0x00007FF86BFC0000                      _multiarray_umath.cp310-win_amd64.pyd  
0x00007FF8B77D0000                      _multiarray_tests.cp310-win_amd64.pyd  
0x00007FF8B77B0000 3.10.13150.1013      _socket.pyd  
0x00007FF8F7550000 10.0.19041.3570      IPHLPAPI.DLL  
0x00007FF8CA840000 3.10.13150.1013      select.pyd  
0x00007FF8B73F0000 3.10.13150.1013      _ctypes.pyd  
0x00007FF8CA790000                      libffi-7.dll  
0x00007FF86BDB0000                      _umath_linalg.cp310-win_amd64.pyd  
0x00007FF8B5CF0000                      _pocketfft_internal.cp310-win_amd64.pyd  
0x00007FF86BD20000                      mtrand.cp310-win_amd64.pyd  
0x00007FF8B47E0000                      bit_generator.cp310-win_amd64.pyd  
0x00007FF8B4360000                      _common.cp310-win_amd64.pyd  
0x00007FF8C45C0000 3.10.13150.1013      _hashlib.pyd  
0x00007FF857D70000 3.1.2.0              libcrypto-3.dll  
0x00007FF8A71F0000                      _bounded_integers.cp310-win_amd64.pyd  
0x00007FF8B3FC0000                      _mt19937.cp310-win_amd64.pyd  
0x00007FF8A8310000                      _philox.cp310-win_amd64.pyd  
0x00007FF8A6CE0000                      _pcg64.cp310-win_amd64.pyd  
0x00007FF8C31C0000                      _sfc64.cp310-win_amd64.pyd  
0x00007FF86BC70000                      _generator.cp310-win_amd64.pyd  
0x00007FF89C0A0000 3.10.13150.1013      _bz2.pyd  
0x00007FF886870000 3.10.13150.1013      _lzma.pyd  
0x00007FF8C3030000 3.10.13150.1013      _queue.pyd  
0x00007FF8BBC10000 3.10.13150.1013      _multiprocessing.pyd  
0x00007FF882270000 3.10.13150.1013      _elementtree.pyd  
0x00007FF870100000 3.10.13150.1013      pyexpat.pyd  
0x00007FF86EA60000 3.10.13150.1013      _ssl.pyd  
0x00007FF86BB80000 3.1.2.0              libssl-3.dll  
0x00007FF8F78B0000 10.0.19041.3570      mswsock.dll  
0x00007FF86BA60000 3.10.13150.1013      unicodedata.pyd  
0x00007FF8BAC10000 3.10.13150.1013      _uuid.pyd  
0x00007FF86BA20000 14.29.30139.0        VCOMP140.DLL  
0x00007FF8C3250000                      hiprt0200064.dll  
0x00007FF8D4FC0000 31.0.15.4601         nvcuda.dll  
0x00007FF8D3580000 31.0.15.4601         nvcuda64.dll  
0x00007FF8ECE00000 31.0.15.4601         nvapi64.dll  
0x00007FF817550000 8.0.0.0              nvoptix.dll  

# Python backtrace
1 Like

It is not a 4.0 issue specifically. Blender tended to do that as far back as in 2015. And even maybe farther back. I use a workaround. I posted it on a similar thread.

How do I go about using scripts? I don’t even know how to analyze a crash log properly.

1 Like

It’s not a Blender Script. It’s a python script which launches blender for every next frame. So it will never be a problem if it crashes.

Here I explain every single line of code in the script.

To run it, you need to save it into a file with a .py extension and open that file with Python 3.

Doesn’t work.

How did you run it?

Your instructions are far from simple so I assumed I should open CMD as admin, CD to where the script is, and run it with

python3 RenderScript.py MFF 2023.blend D:\Blender\Furry\Xodiz\mff png\1 PNG 0 1356

give it the full path of the file too

And it doesn’t need admin I think. Actually I don’t know I don’t use Windows.

As much as I appreciate the help, instead of giving me a workaround for an OS you don’t even use, I would much prefer a solution. If this has happened since 2015, why isn’t there a fix yet?

1 Like

I guess perhaps nobody reported a bug or they don’t see it as a bug.

There’s not one solution or even one bug here- what you’re seeing can be caused by thousands of different bugs, and the given workaround only works for one of them. Usually, switching to a LTS version of Blender fixes this, but again, there’s really no way to say for sure

Problem is, my scene uses and needs light linking to pull off it’s lighting feats. I guess I’ll render it as many times as it takes, starting after the last frame before each crash. It can churn out around 100 frames each time so it’s not that bad.

1 Like

BlenderKit licensing doesn’t allow an artist to share the file?

The script that I wrote should be system agnostic. It just will require full paths of every file you input into it. In the case of Windows it should start with C:\ and stuff.

So

python3 RenderScript.py C:\Files\SomeFolder\2023.blend D:\Blender\Furry\Xodiz\mff\png\ PNG 0 1356

1 Like

Also avoid folder names with a spacebar. If CMD is anywhere near Gnu / Linux Bash Terminal, then if your path contains a space bar you can enclose it into " "

There were assets other than BlenderKit.

got the same problem. I have great specs. Previous Versions were working fine. I tried AGX. Renders 36 frames then crashes. everytime. Even I try rendering 37th frame and above. If you check the location. you ll see that even if you render the rest of the frames. they will not be saved. Dont know what to do. maybe try a previous version.

I encountered the blender render crashing with 4.1 on a 10,000+ frame render. I wanted to let it go overnight and be done the next day, but it extended to multiple days as I had to keep restarting at the frame after the crash. So far, I have only tested with a 10 frame test file, but I’ll edit with results of the thousands of frames test when I get to that point.

I used your code and expanded on it a bit as follows:

  • new command line argument for filename prefix (i.e. my_super_render_00001)
  • new argument for total zero padded character count (I wanted 5)
    *converted number arguments to int at the top of script
  • new variable padded_hashes which holds the correct number of hashes for the blender command line command (i.e. #####)
  • I tweaked the infinite wile True: loop to first check for missing frames, then exit the script if all frames are there, then continue on to render missing frames if needed.
  • fixed/worked around bug where script stops rendering before the last frame (for loop stops one before endframe, so it needs to go to endframe+1)
  • Tweaked the blender command line command to use the file prefix + padded_hashes variable

Here’s my script expanded from @anon31849973 's version:

import sys

# Sample command line with arguments
# python3 bframe.py /Users/myuser/blender-frames/bframes.blend /Users/myuser/blender-frames/Export bframes_ PNG 1 10 5

args = sys.argv

blendfile = args[1]
destination = args[2]
filename_prefix = args[3]
imageformat = args[4]
startframe = int(args[5])
endframe = int(args[6])
padded = int(args[7]) # Resulting zero padded number will be this many characters
padded_hashes = ""

# build zero padding command for blender ##### indicating hash marks for total digits in zero padded number
for i in range(0,padded):
    padded_hashes += "#"

# Convert frame number to blender zero padded frame number
def getnumstr(num):

    # This function turns numbers like 1 or 20 into numbers like 00001 or 00020

    s = ""
    for i in range(padded-len(str(num))):
        s = s + "0"

    return s+str(num)

def getfileoutput(num, FORMAT):

    # Function gives an output filename. From the current frame that's rendering.
    # instead of having frame 1 and format EXR it will give you prefix_00001.exr

    padded_num = getnumstr(num) # Here I'm using the previously defined function
    s = filename_prefix + padded_num

    if FORMAT == "JPEG":
        s = s + ".jpg"
    else:
        s = s + "." + FORMAT.lower()

    return s

# Next we will need to cycle through the files of the destination folder. And render everything that is not rendered yet. But in such a way that if Blender crashes, we will try again immediately.

# A module that can output list of files in a folder
# And can run commands in the terminal
import os

# infinite loop to accommodate possibility of a blender crash and then keep trying.  Will exit infinite loop when it finds all the frames
while True:
    # let's run a already rendered frames check
    missing = 0
    for framenumber in range(startframe,endframe+1):
        imagefilename = getfileoutput(framenumber, imageformat)
        if imagefilename not in os.listdir( destination ):
            missing = 1
    if not missing:
        print("Congratulations, All frames are rendered!")
        exit()

    # if we got to here there are unrendered frames
    # locate first frame needed and start rendering
    for framenumber in range(startframe,endframe+1):
        imagefilename = getfileoutput(framenumber, imageformat)

        # Check if frame is already rendered
        if imagefilename not in os.listdir( destination ):
            # print("Rendering now: "+imagefilename)

            # now render a frame
            #build the command
            cmd_str = "blender -b "+blendfile+" -o "+destination+"/"+filename_prefix+padded_hashes+" -F "+imageformat+" -f "+str(framenumber)
            # print ("Running Command:  "+cmd_str+"\n")
            os.system(cmd_str)

I hope someone finds this useful!

1 Like

I have pimped out the script even more.

  • Now it will handle spaces within the various file paths by quoting those arguments when it builds the blender command arguments (although you also do need to quote or escape those file paths manually in the first python script arguments).
  • Logs render progress to a text file which you can monitor during the render, showing which frame it’s on, how many are left, average render time per frame, and estimated completion time. (Note - the render file currently shows up in the active terminal directory, so cd to the directory where you want the log file to show up, or modify the script to accept an absolute path for the log file)
  • The script design allows for launching multiple instances to speed up the render. For example, if you are rendering 1000 frames, you could start one rendering 1-1000, another 250-1000, another 500-1000, and another 750-1000, which I have successfully done.
  • The main purpose of keeping the render going even when blender crashes was successful. I would have the blender crash dialog pop up sometimes, but the render kept going.
  • The script design will also find and render any missing frames automatically in a “completed” render. If you happened to have frame 750 not rendered in a 1000 frame render, running the script again will find and render frame 750 automatically.

Here’s my latest code:

import sys
import os
import time
import subprocess

args = sys.argv

blendfile = args[1]
destination = args[2]
filename_prefix = args[3]
imageformat = args[4]
startframe = int(args[5])
endframe = int(args[6])
padded = int(args[7])  # Resulting zero padded number will be this many characters
padded_hashes = "#" * padded  # Simplified way to build padded_hashes

render_job = f"{filename_prefix}ff_{startframe}-{endframe}"
log_file_path = f"render_log_{render_job}.txt"  # Path to the log file
log_header = "Starting Render Job: " + render_job + "\n\n"
log_output = log_header

with open(log_file_path, "a") as log_file:
    log_file.write(log_output)

# Variables to track render time
total_render_time = 0
rendered_frames = 0
start_time = time.time()

# Convert frame number to blender zero padded frame number
def getnumstr(num):
    return str(num).zfill(padded)

def getfileoutput(num, FORMAT):
    padded_num = getnumstr(num)
    s = f"{filename_prefix}{padded_num}.{FORMAT.lower()}"
    return s

def format_time(seconds):
    hours, remainder = divmod(seconds, 3600)
    minutes, seconds = divmod(remainder, 60)
    return "{:02}:{:02}:{:02}".format(int(hours), int(minutes), int(seconds))

log_body = ""
log_end = "\nCongratulations, All frames are rendered!\n"

# Infinite loop to accommodate the possibility of a blender crash
while True:
    missing = False
    total_to_render = 0
    for framenumber in range(startframe, endframe + 1): # python for loop will finish 1 before endframe, so we + 1 to include endframe
        imagefilename = getfileoutput(framenumber, imageformat)
        if imagefilename not in os.listdir(destination):
            total_to_render += 1
            missing = True
            log_body = ""
            # break
    if not missing:
        print(log_end)
        with open(log_file_path, "w") as log_file:
            log_file.write(log_header + log_body + log_end)
        break

    for framenumber in range(startframe, endframe + 1):
        imagefilename = getfileoutput(framenumber, imageformat)

        if imagefilename not in os.listdir(destination):
            # Measure render time for each frame
            frame_start_time = time.time()

            # Build the command
            cmd_str = f"blender -b \"{blendfile}\" -o \"{destination}/{filename_prefix}{padded_hashes}\" -F {imageformat} -f {framenumber}"

            # Use subprocess.Popen for non-blocking execution
            process = subprocess.Popen(cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

            # Wait for the process to terminate
            process.wait()

            frame_end_time = time.time()
            frame_render_time = frame_end_time - frame_start_time
            total_render_time += frame_render_time
            rendered_frames += 1

            # Calculate time elapsed
            time_elapsed = time.time() - start_time
            time_elapsed_formatted = format_time(time_elapsed)

            frames_remaining = total_to_render - rendered_frames

            log_body = f"Frame #: {framenumber}:\n"
            log_body += f"{rendered_frames} of {total_to_render}, {frames_remaining} remaining.\n"
            log_body += f"Time Elapsed: {time_elapsed_formatted}\n"
            average_render_time = total_render_time / rendered_frames
            estimated_time_remaining = average_render_time * frames_remaining
            formatted_remaining_time = format_time(estimated_time_remaining)
            log_body += f"Average per Frame: {average_render_time:.2f} seconds\n"
            log_body += f"Remaining frames: {frames_remaining}\n"
            log_body += f"Estimated Time Remaining: {formatted_remaining_time}\n"

            # Calculate estimated time remaining
            if frames_remaining > 0:

                with open(log_file_path, "w") as log_file:
                    log_file.write(log_header + log_body)
            else:
                log_body += "\nFinished rendering frames!\n"

# No need to close the log file, 'with' statement takes care of that