Doors open Friday 4:00 PM — arrive early to check inDoors Friday 4:00 PM — arrive early
Embodied Metal Hackathon
Get API Key

Reference

Troubleshooting

Symptom → fix

~7 min read

The debugging agent

Broke a step? Copy this into any coding agent. It reads this page and your kit’s README, asks you for the exact error, and works symptom-first until the failing step’s check passes.

Debugging agent
A step in The Embodied Metal Hackathon setup is broken. Help fix it.

Fetch https://missionrobotics.ai/hackers/llms.txt and https://missionrobotics.ai/hackers/troubleshooting.md, and the README of the SO-101 kit (https://github.com/mission-robotics-ai/so100-hackathon). Ask the user for the exact command they ran and the exact error text it printed — do not guess.

Work symptom-first: match their error to an entry on the troubleshooting page, apply that fix, and run only that step's check.

Finish line: the "You should see" checkpoint for the failing step passes.

Already working inside a coding agent? pixi run newt skill install drops the newt-onboarding guide into .claude/skills/ so the agent has the setup steps on hand — there is no separate debugging skill.

When a step breaks, find the line that matches what your terminal actually printed, run the fix under it, and re-check that one step. The entries follow the guide's order — setup first, calling your model last.

Install & setup

pixi run learn crashes with OSError: [Errno 48] Address already in use. Something is already using port 3000 — usually a pixi run learn left running from an earlier session or another local dev server. Check what's holding the course's ports and free it.

pixi run ports
You should see

all course ports are free (9876 proxy, 51234 catalog, 8000 control API, 3000 course site) — or the process holding 3000 named, so you can stop it.

Installing newt separately (optional)

newt now arrives bundled with the kit's pixi install; the entries below only apply if you'd rather install it globally instead.

uv tool install fails to find an interpreter, or dies building torch. The newt CLI supports Python 3.11 through 3.13; 3.14 and newer hit a torch compatibility wall. Pin the interpreter when you install.

uv tool install --python 3.12 "git+https://github.com/new-theory-research/newt-python.git"
You should see

the install resolve and newt --help print its usage.

newt: command not found right after a clean install. uv installed the CLI into ~/.local/bin, which your shell does not search yet.

uv tool update-shell
You should see

newt resolve in a new shell.

git@github.com: Permission denied (publickey) while installing. The documented command uses an SSH URL, which needs a GitHub SSH key; every hackathon repo is public, so switch the URL to HTTPS and no key is needed.

uv tool install "git+https://github.com/new-theory-research/newt-python.git"
You should see

the install pull the repo over HTTPS without asking for a key.

Drive & cameras

Calibration

The clean-start ritual. Every calibration failure below gets rarer if you start the same way each time (a beta tester who hit most of them worked this out live):

  1. Fold both arms to a rest pose — upright and compact, not sprawled on the table. Calibration starts from wherever the arm is, so a repeatable start beats a random one.
  2. Run Ping and wiggle each joint on both arms — watch each one move in the viewer. This proves the machine has a live, exclusive connection to both arms before you calibrate.
  3. During the sweep step, watch the MIN/POS/MAX numbers move as you move the arm. Numbers sitting still while the arm moves mean the connection is stale — stop, go back to Ping, start over.
  4. If a run fails partway, restart from Ping rather than pushing through — a clean start costs a minute; a half-applied state costs many.

The sweep's MIN/MAX numbers don't change while you move the arm. The readings aren't live — usually another kit tool is still talking to the arms (a teleop or logging run left open in a terminal, or another calibrate). Only one tool can drive the arms at a time. Close the other run, go back to Ping, confirm each joint moves in the viewer, then calibrate again.

pixi run calibrate-so100 (or the site's Calibrate step) fails at the middle-pose step with homing verification failed (expected ~2047), naming several joints reading values hundreds of ticks off — and retrying with the arm held still fails the same way every time. Some SO-101 servo firmware batches silently drop the calibration writes after the first one while still acknowledging them; holding stiller can't fix a write that never landed. Update the kit, then re-run calibration — the updated kit waits for readings to stabilize before measuring, which resolved this on the event's own arms.

git pull
pixi run calibrate-so100
You should see

the middle-pose step pass, every joint reading ~2047. (If it still fails, the error now names the exact servo — take that to a mentor.)

Calibration fails naming one joint, typically gripper reads <far from 2047>. That joint moved between the offset write and the verification read — on the leader, the gripper handle springs closed as your hand shifts to press Enter. Update the kit first — it now tolerates brief wobble — then rest the arm on something stable in a roughly-middle pose and wedge the gripper half-open with a marker or pen; the gray target only needs to be approximate.

git pull
pixi run calibrate-so100
You should see

calibration pass with all joints ~2047.

Calibration fails after the sweep step with sweep incomplete for: <joints> (each joint needs >= 300 ticks of motion). Nothing is broken — the error itself confirms the homing offsets were written. The sweep step records each joint's travel limits, and every joint has to physically move through its range before you press Enter. Re-run, and at the sweep step work the arm one joint at a time — base fully left and right, shoulder fully up and down, elbow through its whole arc, wrist flex end to end, wrist roll both ways, gripper fully open and closed — then press Enter.

pixi run calibrate-so100 leader
You should see

the sweep step pass and the calibration file written; joints you swept fully drop out of the error if you re-run short.

Calibration still fails after updating the kit. First confirm the update took: git log --oneline -1 in your kit clone should show a commit from July 17 or later. Then power-cycle the arm — unplug its power barrel and USB, plug both back in, and re-run calibration. The servos load their stored settings at power-on, which clears any half-applied state left by earlier failed attempts.

git pull
pixi run calibrate-so100 leader
You should see

calibration pass after the power-cycle. If it still fails, the error now names the exact servo and readings — copy it (the site's error box has a copy button) and bring it to a mentor.

pixi run log-so100 finds only skipped cameras, or none. The built-in webcam and iPhone Continuity cameras are never auto-selected, and macOS blocks camera access until you grant it. Plug in an external webcam, allow your terminal under System Settings → Privacy & Security → Camera, then probe what the kit sees.

pixi run check-cameras
pixi run log-so100 -- --cameras 2
You should see

each recording camera stream live in the viewer.

A pixi run command from an older guide errors that the task doesn't exist. The kit moves fast and renames or removes tasks between versions — dataset-collector on port 8000 is now record-episode plus pixi run so100-server. List the tasks the kit actually ships and follow its current README.

pixi run
You should see

the kit's live task names; use those, not the ones from a cached page.

Teleop logs, but the follower never mirrors the leader. Teleoperation needs both arms calibrated; with one arm the kit drops silently to logging with no action stream, and a recording with no actions can't train. Calibrate each arm, then start teleop.

pixi run calibrate-so100 leader
pixi run calibrate-so100 follower
pixi run teleop-so100
You should see

the follower track the leader smoothly.

Record

Episodes export with no instruction, and the fine-tune learns nothing. The model is language-conditioned, and the kit leaves the task field empty unless you set it, so a placeholder or blank label trains on nothing. Pass the same plain instruction on every take.

pixi run record-episode -- --dataset my_task --task "pick up the red cube and place it in the bin" --tag "Good episode"
You should see

your instruction on each episode: pixi run query-dataset (bare) lists your datasets by name, then pixi run query-dataset -- --dataset <name> prints the per-episode table.

export-lerobot writes fewer takes than you recorded, or none. By default the export keeps only takes tagged "Good episode". Tag the good ones as you record, or export everything with an empty tag.

pixi run export-lerobot -- --dataset my_task --repo-id <you>/my_task --tag ""
You should see

datasets/<you>/my_task/meta/info.json written.

Upload & fine-tune

The examples below call newt finetune directly — the underlying command pixi run finetune -- --dataset <name> wraps and runs for you. pixi run finetune -- --dry-run prints the exact newt finetune line it would run, without uploading anything.

newt finetune rejects the folder in seconds, before uploading. It validates the export on your laptop first — a folder missing meta/info.json, or without readable action and observation.state shapes, isn't a LeRobot dataset. Re-export from the kit and point at the exported directory.

newt finetune --dataset ./datasets/<you>/my_task
You should see

uploading … staged as my_task, then a job handle.

The run stops with failed at gate: intake. The dataset is staged nowhere the pipeline can reach — a bare name was passed that was never uploaded. The message names both places it looked; pass the folder path so the command uploads first, then launches.

newt finetune --dataset ./datasets/<you>/my_task
You should see

the upload run, then the launch confirmation and a job handle.

newt finetune --handle <job> --status shows the model tag as (pending — not yet assigned). The tag is minted only when the run succeeds, so a pending tag means the run hasn't finished, not that it failed. Re-check the handle.

newt finetune --handle <job> --status
You should see

your model's tag once the run reaches a succeeded state.

Calling your model

Any call raises newt.AuthError. Your key is wrong, revoked, or just not visible in this shell — a fresh terminal doesn't inherit it. Re-authenticate, then confirm.

pixi run newt login
pixi run newt models
You should see

pixi run newt models list the models your key can drive.

The first call warns ColdStartRetry and waits up to a minute. Your model is live; its GPU container is warming, and 30 to 90 seconds is normal. Wait — it answers on its own. Only past the 180-second window does it raise TimeoutError, which means call again.

You should see

the call return action chunks once the container is warm.

The arm runs but moves to the wrong poses, with no error. Train-time and inference-time calibration disagree, so the same joint angle means two different physical positions. Launch the deploy client with the calibration id your data was recorded under.

--robot.id=<USB_ID>
You should see

the arm track the poses your demonstrations taught.

The full installation and troubleshooting reference