Is there an existing issue for this?
Current Behavior:
When a review is published with render_target = farm from a headless Nuke session (nuke -t), the bake script written by ExporterReviewMov (<review>.nk, e.g. renderXXX.mov.nk) can be generated without the temporary bake Write node it is supposed to contain. The Deadline render job is told to render that Write node (bakeWriteNodeName, e.g. Write1), cannot find it in the loaded script, and fails immediately with:
RuntimeError: Nothing is named "Write1"
Root cause is in ExporterReviewMov.generate_mov() (client/ayon_nuke/api/plugin.py). The bake .nk is produced by copying the on-disk workfile — save_file() → shutil.copyfile(context["currentFile"], <bake>.nk) — which relies on a preceding nuke.scriptSave() having first flushed the in-memory bake Write node to disk. But nuke.scriptSave() is a no-op whenever root.modified() is False. In a headless publish the workfile is saved (which clears the modified flag) and the bake graph is then built purely via the Python API (nuke.createNode / connectInput), which does not re-set the flag — so scriptSave() silently does nothing and the copied bake .nk is missing the Write node. In an interactive GUI session the flag is effectively always True by publish time, so the bug is not observed there.
The same no-op also affects the second nuke.scriptSave() at the end of generate_mov() (after clean_nodes()), whose job is to restore the workfile once the temporary bake nodes are removed — so under headless the transient bake Write node can additionally be left behind in the published workfile.
Expected Behavior:
The farm bake .nk should always contain the bake Write node named in bakeWriteNodeName, so the Deadline render job can render it — regardless of whether the publish runs interactively or headless. The workfile should also be left clean (no leftover bake Write node) after publish.
Version
1.9.8
What platform you are running on?
Windows, Linux / RedHat, MacOS
Steps To Reproduce:
- Publish a Nuke review with
render_target = farm from a headless session (nuke -t) — e.g. any automated/batch publish.
- Inspect the generated bake script
<review>.nk under .../renders/nuke/<review>/ — it does not contain the bakeWriteNodeName Write node (only the comp's own nodes).
- The Deadline bake job loads that
.nk and crashes with RuntimeError: Nothing is named "Write1".
Minimal, AYON-free reproduction of the underlying scriptSave() no-op (run with nuke -t repro.py):
import nuke, os, shutil, tempfile
wf = os.path.join(tempfile.gettempdir(), "wf.nk")
bake = os.path.join(tempfile.gettempdir(), "bake.nk")
nuke.scriptClear()
nuke.createNode("Constant").setName("Comp")
nuke.scriptSaveAs(wf, overwrite=1)
nuke.root().setModified(False) # publish saves the workfile, clears the flag
nuke.createNode("Write").setName("Write1") # bake node built via the API
print("modified:", nuke.root().modified()) # False
nuke.scriptSave(); shutil.copyfile(wf, bake)
print("scriptSave -> bake has Write1:", "name Write1" in open(bake).read()) # False (bug)
nuke.scriptSaveAs(wf, overwrite=1); shutil.copyfile(wf, bake)
print("scriptSaveAs -> bake has Write1:", "name Write1" in open(bake).read()) # True (fixed)
Are there any labels you wish to add?
Relevant log output:
Additional context:
Suggested fix — replace both bare nuke.scriptSave() calls in generate_mov() with a forced save to the same path, which writes regardless of the modified flag and avoids renaming root.name() / project_directory:
# farm branch, before save_file():
nuke.scriptSaveAs(self.instance.context.data["currentFile"], overwrite=1)
# end of generate_mov(), after clean_nodes():
nuke.scriptSaveAs(self.instance.context.data["currentFile"], overwrite=1)
Saving to the bake path directly is deliberately avoided: it would rename the live session (root.name() / project_directory) and fire onScriptSave callbacks — the very reason save_file() uses shutil.copyfile instead of scriptSaveAs. No behavioural change for GUI/local publishes (the local render() branch does not depend on the saved .nk, and the modified flag is already True interactively).
Verified: the standalone repro above (Nuke 15.0v2 / macOS, Nuke 15.2v1 / Linux) confirms modified() stays False after createNode under nuke -t, scriptSave() no-ops, and scriptSaveAs(overwrite=1) writes reliably. A full headless farm publish (Nuke 15.2 + Deadline) confirms the bake .nk then contains the Write node and the render job completes.
Version
ayon-nuke 0.4.11
Workaround
Publish reviews interactively (GUI) rather than headless, or disable Extract Review Intermediates for headless farm submissions. Both are temporary fixes only — the fix above resolves it in all modes.
Is there an existing issue for this?
Current Behavior:
When a review is published with
render_target = farmfrom a headless Nuke session (nuke -t), the bake script written byExporterReviewMov(<review>.nk, e.g.renderXXX.mov.nk) can be generated without the temporary bake Write node it is supposed to contain. The Deadline render job is told to render that Write node (bakeWriteNodeName, e.g.Write1), cannot find it in the loaded script, and fails immediately with:Root cause is in
ExporterReviewMov.generate_mov()(client/ayon_nuke/api/plugin.py). The bake.nkis produced by copying the on-disk workfile —save_file()→shutil.copyfile(context["currentFile"], <bake>.nk)— which relies on a precedingnuke.scriptSave()having first flushed the in-memory bake Write node to disk. Butnuke.scriptSave()is a no-op wheneverroot.modified()isFalse. In a headless publish the workfile is saved (which clears the modified flag) and the bake graph is then built purely via the Python API (nuke.createNode/connectInput), which does not re-set the flag — soscriptSave()silently does nothing and the copied bake.nkis missing the Write node. In an interactive GUI session the flag is effectively alwaysTrueby publish time, so the bug is not observed there.The same no-op also affects the second
nuke.scriptSave()at the end ofgenerate_mov()(afterclean_nodes()), whose job is to restore the workfile once the temporary bake nodes are removed — so under headless the transient bake Write node can additionally be left behind in the published workfile.Expected Behavior:
The farm bake
.nkshould always contain the bake Write node named inbakeWriteNodeName, so the Deadline render job can render it — regardless of whether the publish runs interactively or headless. The workfile should also be left clean (no leftover bake Write node) after publish.Version
1.9.8
What platform you are running on?
Windows, Linux / RedHat, MacOS
Steps To Reproduce:
render_target = farmfrom a headless session (nuke -t) — e.g. any automated/batch publish.<review>.nkunder.../renders/nuke/<review>/— it does not contain thebakeWriteNodeNameWrite node (only the comp's own nodes)..nkand crashes withRuntimeError: Nothing is named "Write1".Minimal, AYON-free reproduction of the underlying
scriptSave()no-op (run withnuke -t repro.py):Are there any labels you wish to add?
Relevant log output:
Additional context:
Suggested fix — replace both bare
nuke.scriptSave()calls ingenerate_mov()with a forced save to the same path, which writes regardless of the modified flag and avoids renamingroot.name()/project_directory:Saving to the bake path directly is deliberately avoided: it would rename the live session (
root.name()/project_directory) and fireonScriptSavecallbacks — the very reasonsave_file()usesshutil.copyfileinstead ofscriptSaveAs. No behavioural change for GUI/local publishes (the localrender()branch does not depend on the saved.nk, and the modified flag is alreadyTrueinteractively).Verified: the standalone repro above (Nuke 15.0v2 / macOS, Nuke 15.2v1 / Linux) confirms
modified()staysFalseaftercreateNodeundernuke -t,scriptSave()no-ops, andscriptSaveAs(overwrite=1)writes reliably. A full headless farm publish (Nuke 15.2 + Deadline) confirms the bake.nkthen contains the Write node and the render job completes.Version
ayon-nuke 0.4.11
Workaround
Publish reviews interactively (GUI) rather than headless, or disable
Extract Review Intermediatesfor headless farm submissions. Both are temporary fixes only — the fix above resolves it in all modes.