bambuddy/slicer-api
maziggy a849759469 Explain an oversized model instead of reporting a slicer crash (#2802)
The sidecar caps model uploads and reports a rejection as a bare
HTTP 500 "File too large" -- multer's MulterError is not the sidecar's
AppError, so its handler falls through to the default status. A 500
reads as a crash inside the slicer, and the one message Bambuddy had
about request size was written for the 413 a reverse proxy sends, so
it never appeared. The reporter tried MAX_FILE_SIZE, BODY_PARSER_LIMIT
and EXPRESS_PAYLOAD_LIMIT, stopped nginx, and moved from Windows to
Docker -- none of which the sidecar reads.

Match the rejection by what it says rather than by its status, so an
installation still on an older sidecar image gets the same explanation.
The 500 match is strict -- the body must be only multer's message --
because a genuine CLI failure is also a 500 and has to keep reaching
the embedded-settings fallback. Old images are told to update, since
they have no setting to change; current ones are told which one to set.

Raising SlicerInputError rather than SlicerApiServerError is also what
skips the fallback retry, which had been re-uploading the identical
oversized file after a second 25-second 3MF conversion.

Log the model size on every slice. Nothing recorded it, so a support
package from a slice that died on an upload cap looked exactly like one
that died on a bad profile, and this had to be sized by hand.

Fall back to the exception class name when a transport error stringifies
empty -- three lines of the reporter's log read "Slicer sidecar
unreachable: " and stopped there.

Needs a sidecar image update to take full effect; MAX_MODEL_UPLOAD_MB is
documented in slicer-api/.env.example.
2026-08-10 12:18:29 +02:00
..
.env.example Explain an oversized model instead of reporting a slicer crash (#2802) 2026-08-10 12:18:29 +02:00
.gitignore
docker-compose.yml Explain an oversized model instead of reporting a slicer crash (#2802) 2026-08-10 12:18:29 +02:00
README.md docs(slicer-api): switch sidecar to pre-built images on GHCR + Docker Hub (#1657) 2026-06-06 13:06:45 +02:00

Slicer-API sidecar (optional)

Self-contained Docker Compose stack that runs HTTP wrappers around the OrcaSlicer and/or Bambu Studio CLI. Bambuddy's Slice action calls these to slice models server-side, no desktop slicer required.

This folder is optional. Bambuddy works without it — Slice falls back to opening the model in the user's local desktop slicer via URI scheme. Enable the API path by:

  1. Starting one or both services here
  2. Settings → Slicer → Use Slicer API = on
  3. Set Slicer sidecar URL for whichever slicer you've started

Quick start

cd slicer-api/
cp .env.example .env       # edit ports if you like

# OrcaSlicer only (default profile):
docker compose up -d
curl http://localhost:3003/health

# Both slicers:
docker compose --profile bambu up -d
curl http://localhost:3001/health   # bambu-studio-api
curl http://localhost:3003/health   # orca-slicer-api

First start pulls pre-built images from GHCR (~110 MB OrcaSlicer, ~220 MB BambuStudio). No local build, no git in the BuildKit worker, works on QNAP / Synology / Container Station out of the box.

Both images are linux/amd64 only. OrcaSlicer's ARM64 build is on hold pending an upstream extraction fix; BambuStudio doesn't publish ARM64 at all. For ARM64 hosts (Raspberry Pi 4/5, Apple Silicon Linux), run the sidecar on a separate x86_64 box and point Bambuddy at it via the Sidecar URL field — the sidecar doesn't need to live next to Bambuddy.

Ports

Service Default host port Why this port
orca-slicer-api 3003 Bambuddy's virtual-printer feature reserves 3000 and 3002
bambu-studio-api 3001 First free port in that range

Override via ORCA_API_PORT / BAMBU_API_PORT in .env.

Bambuddy wiring

In the Bambuddy UI: Settings → Slicer:

  • Preferred Slicer: pick OrcaSlicer or Bambu Studio.
  • Use Slicer API: turn on.
  • Sidecar URL: paste the full URL of the chosen slicer's sidecar. Default values match the Compose defaults:
    • OrcaSlicer: http://localhost:3003
    • Bambu Studio: http://localhost:3001

Leaving the URL field blank uses the SLICER_API_URL / BAMBU_STUDIO_API_URL environment defaults from Bambuddy's config.

Where the images live

Pre-built images are published to two registries on every Bambuddy stable release:

  • ghcr.io/maziggy/orca-slicer-api:latest / docker.io/maziggy/orca-slicer-api:latest
  • ghcr.io/maziggy/bambu-studio-api:latest / docker.io/maziggy/bambu-studio-api:latest

Each release also publishes a versioned tag (:bambuddy-X.Y.Z) so you can pin to the sidecar that shipped alongside a specific Bambuddy release — set SIDECAR_TAG=bambuddy-0.2.5 in .env.

Both images are built from the maziggy/orca-slicer-api fork (bambuddy/profile-resolver branch). The fork patches AFKFelix's upstream wrapper with the inherits: chain resolver, from: "User""system" rewrite, # clone-prefix strip, and sentinel-value strip — all empirically required to slice real GUI exports without segfaulting the CLI. Once those land upstream, the compose file can be flipped back to ghcr.io/afkfelix/orca-slicer-api.

Updating

docker compose pull
docker compose --profile bambu up -d

That's it — Compose pulls the current :latest (or whatever SIDECAR_TAG you've pinned to) and recreates the containers.

To roll back to the sidecar that shipped with a previous Bambuddy release, set SIDECAR_TAG=bambuddy-X.Y.Z in .env and re-run the two commands above.

Troubleshooting

  • address already in use on port 3000 or 3002 — Bambuddy's virtual-printer feature owns those. Don't change ORCA_API_PORT to 3000 or 3002.

  • /health reports version: "unknown" — cosmetic. The bundled binary works; the wrapper just couldn't parse the version string from the slicer's --help output (BambuStudio's format differs from OrcaSlicer's, which is what the wrapper was tuned for).

  • Slice returns "Failed to slice the model" — the wrapper hides the CLI's stderr. Re-run inside the container to see it:

    docker exec orca-slicer-api /app/squashfs-root/AppRun --slice 1 \
        --load-settings "/path/to/printer.json;/path/to/preset.json" \
        --load-filaments /path/to/filament.json \
        --allow-newer-file --outputdir /tmp/out /path/to/model.3mf