Skip to content

Make the CLI able to slice: fix the version check and two null GUI crashes - #839

Open
KuzuriAo wants to merge 2 commits into
Snapmaker:mainfrom
KuzuriAo:cli-slice-fixes
Open

Make the CLI able to slice: fix the version check and two null GUI crashes#839
KuzuriAo wants to merge 2 commits into
Snapmaker:mainfrom
KuzuriAo:cli-slice-fixes

Conversation

@KuzuriAo

@KuzuriAo KuzuriAo commented Sep 9, 2026

Copy link
Copy Markdown

Make the CLI able to slice: fix the version check and two null GUI crashes

As shipped, Snapmaker_Orca on the command line cannot slice anything. Every file is rejected on a version check, and if you get past that with --allow-newer-file the process segfaults. That rules out any scripted or server side use of the slicer.

There are three independent defects: one in the version check, and two places where GUI-only code is reached headless. The first two are fixed by matching what upstream OrcaSlicer already does. The third is in code that only exists in this fork.

Defect 1: the version check rejects every project file

src/Snapmaker_Orca.cpp compares the loaded file's version against SLIC3R_VERSION. That is a legacy constant inherited from BambuStudio, defined in src/common_func/common_func.hpp as 01.10.01.50, and it does not track the product version, which sits right next to it as Snapmaker_VERSION "2.3.6". Real project files report major version 2, the constant reports major 1, so the major versions never match and everything is refused:

Version Check: File Version 2.3.0.6 not supported by current cli version 01.10.01.50

That file was saved by Snapmaker Orca itself, so the CLI cannot even read its own output.

The comparison has a second problem. cli_ver.maj() != file_version.maj() || cli_ver.min() < file_version.min() rejects files older than the application as well as newer ones, and evaluates the minor version even when the major versions differ.

Upstream OrcaSlicer (src/OrcaSlicer.cpp) compares against its product version and only rejects files that are genuinely newer:

Semver cli_ver = *Semver::parse(SoftFever_VERSION);
if (!allow_newer_file && ((cli_ver.maj() < file_version.maj()) ||
    ((cli_ver.maj() == file_version.maj()) && (cli_ver.min() < file_version.min()))))

This PR adopts exactly that, using Snapmaker_VERSION, and reports the product version in the error message instead of the legacy constant.

Defect 2: null GUI application in CLI mode

With the version check passed, the process dies immediately:

stop reason = EXC_BAD_ACCESS (code=1, address=0x398)
frame #0: Slic3r::GUI::GUI_App::em_unit(this=0x0000000000000000) const at GUI_App.hpp:517
          int em_unit() const { return m_em_unit; }

PartPlate::generate_plate_name_texture() calls wxGetApp().em_unit() to scale the plate name font. Headless there is no application object, so it dereferences null.

Upstream guards the same function by returning early when there is no 3D canvas, since without one there is no texture to generate. This PR does the same, with one addition: the CLI path here reaches the function with a null Plater, so the guard null checks m_partplate_list and m_plater before fetching the canvas. Fetching it directly, as upstream does, crashes inside the guard itself. Upstream uses this same defensive form elsewhere in the file.

The canvas is then reused later in the function rather than being fetched a second time, which also matches upstream.

Defect 3: null GUI application in expand_plate_extruders()

With both of the above fixed, a plain single filament project still crashed:

stop reason = EXC_BAD_ACCESS (code=1, address=0x868)
frame #0: Slic3r::GUI::GUI_App::filaments_cnt(this=0x0000000000000000) const at GUI_App.cpp:6832
          return preset_bundle->filament_presets.size();

expand_plate_extruders() in src/slic3r/GUI/PartPlate.cpp calls wxGetApp().filaments_cnt() and wxGetApp().preset_bundle to expand virtual extruder ids for mixed filaments. It is called from PartPlate::get_extruders(), which the CLI always reaches. Unlike the first two defects this code has no upstream counterpart, it came in with mixed filament support.

This PR returns early when there is no application object. In CLI mode there is no GUI preset bundle to expand ids against, so they are left as they are, which is what happened before mixed filament support existed. The GUI path is unchanged, since wxTheApp is always present there.

Testing

Built from main, macOS Apple Silicon. Compared against the released Snapmaker Orca 2.3.6, which reports the same version, so the only difference is these commits.

The test file is a cone exported from Snapmaker Orca's own GUI: single filament, one plate, by layer, default settings, 35 KB. Its embedded version is 2.3.6, the same as the application reading it. It is attached to this PR.

Each case below runs the identical command with a fresh datadir, so nothing carries between runs:

TestSlice.3mf.zip

rm -rf /tmp/snapmaker-cli-test && mkdir -p /tmp/snapmaker-cli-test/datadir /tmp/snapmaker-cli-test/out

Snapmaker_Orca \
  --datadir /tmp/snapmaker-cli-test/datadir \
  --slice 0 \
  --export-3mf TestSlice.gcode.3mf \
  --outputdir /tmp/snapmaker-cli-test/out \
  TestSlice.3mf

Released 2.3.6, as a user would run it

exit code : 232
error     : Version Check: File Version 2.3.0.6 not supported by current cli version 01.10.01.50
output    : none produced

Released 2.3.6, with the version check bypassed via --allow-newer-file

exit code : 139  (SIGSEGV)
output    : none produced

This case matters: it shows the crashes are separate defects and not a consequence of the version check.

This branch, as a user would run it

exit code : 0
output    : file.gcode.3mf, 446570 bytes
contains  : 1 gcode file(s)
stat      : key="prediction" value="943"
stat      : key="weight" value="2.35"

Also checked on this branch, since the crashes were reached by different code paths:

  • a multi object by-object project: exit 0
  • a five filament converted project (with --allow-newer-file, since its application tag claims a newer version): exit 0, 35 MB output

The GUI is unaffected. generate_plate_name_texture() only returns early when there is no 3D canvas, and expand_plate_extruders() only when there is no application object, neither of which happens with a window open. The version check is not on the GUI load path.

Why this matters

The immediate motivation is a publishing pipeline: converted project files need to be sliced headlessly so that print time and filament usage can be shown alongside them. Any automated workflow, batch conversion, regression testing, or server side slicing needs a working CLI. Right now upstream OrcaSlicer's CLI has to be used instead, which means not using the Snapmaker profiles and G-code the fork exists to provide.

One small note for anyone reproducing: --allow-newer-file is a bare boolean. Passing a value, as in --allow-newer-file 1, makes the 1 be parsed as an input filename and fails with No such file: 1.

The CLI compares a loaded file's version against SLIC3R_VERSION, which is a
legacy constant inherited from BambuStudio (01.10.01.50 in common_func.hpp)
and does not track the product version (Snapmaker_VERSION, 2.3.6). Since real
project files report major version 2 and the constant reports major 1, the
major versions never matched and every file was rejected with

  Version Check: File Version 2.3.0.6 not supported by current cli version
  01.10.01.50

including files saved by Snapmaker Orca itself.

The comparison was also wrong in the other direction: "cli_ver.maj() !=
file_version.maj() || cli_ver.min() < file_version.min()" rejects files older
than the application as well as newer ones, and evaluates the minor version
across differing major versions.

Match upstream OrcaSlicer (src/OrcaSlicer.cpp), which compares against its
product version and only rejects files newer than the application. Also report
the product version in the error message rather than the legacy constant.
PartPlate reaches wxGetApp() on the headless path in two places. wxGetApp()
dereferences the wx application object, which does not exist in CLI mode, so
slicing from the command line dies with SIGSEGV before producing output.

1) PartPlate::generate_plate_name_texture() calls wxGetApp().em_unit() to
   scale the plate name font:

     stop reason = EXC_BAD_ACCESS (code=1, address=0x398)
     frame #0: Slic3r::GUI::GUI_App::em_unit(this=0x0000000000000000) const
               at GUI_App.hpp:517

   Upstream OrcaSlicer guards this function by returning early when there is
   no 3D canvas, since there is nothing to generate a texture for in that
   case. Do the same, additionally null checking m_partplate_list and
   m_plater before dereferencing them: the CLI path reaches this function
   with a null Plater, so fetching the canvas directly would crash inside the
   guard itself. The canvas is then reused later in the function instead of
   being fetched a second time, which also matches upstream.

2) expand_plate_extruders() calls wxGetApp().filaments_cnt() and
   wxGetApp().preset_bundle to expand virtual extruder ids for mixed
   filaments, and is reached from PartPlate::get_extruders():

     stop reason = EXC_BAD_ACCESS (code=1, address=0x868)
     frame #0: Slic3r::GUI::GUI_App::filaments_cnt(this=0x0000000000000000)
               const at GUI_App.cpp:6832

   Return early when there is no application object. There is no GUI preset
   bundle to expand ids against in CLI mode, so they are left as they are,
   which is what happened before mixed filament support was added. This code
   has no upstream counterpart.

Both guards only trigger when running headless, so the GUI is unaffected:
there is always a 3D canvas and an application object with a window open.
@KuzuriAo

Copy link
Copy Markdown
Author

@zackaree-shen

Thanks again for picking this one up. Two more small macOS fixes went in tonight, both tested, in case they are useful to batch with this:

#852 — a model opened from Space is loaded and then discarded during startup. macOS delivers the URL after launch rather than in argv, so switch_to_3d never gets set and post_init starts a blank project over it.
#856 — opening a second Space model prompts "Open as project / Import geometry only" and defaults to the one that throws away the creator's filament and process settings. The first half is macOS only; the wrong default affects drag-and-drop everywhere.

No rush on either, and happy to split or rework them if you would rather they were shaped differently.

@zackaree-shen

Copy link
Copy Markdown

@KuzuriAo Thanks, I will check it soon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants