Hi @gabrielburnworth,
I’d like to report a bug introduced in commit 573bd63e ([v15.5.0-rc5] use axis_order default setting) in lib/celery/compilers/move_compiler.ex that causes all move commands to fail on self-hosted installations.
Environment
- FarmBot OS: 15.5.1
- Hardware: Raspberry Pi 3 (
rpi3) - Firmware: Farmduino v1.6 (
farmduino_k16) - Web app: self-hosted, master branch (updated 2026-05-16)
- Database: PostgreSQL 16
- Deployment: Docker Compose
Problem
Every move command fails immediately — whether triggered via the map “GO” button, manual coordinate input, or a sequence containing a move node. Homing, Lua scripts, and photo sequences work fine. Only movement is affected.
Error message (from device logs)
Failed to execute command: %FunctionClauseError{
module: String,
function: :split,
arity: 3,
kind: nil,
args: nil,
clauses: nil
}
This error appears consistently every time any move command is executed, regardless of the coordinate values provided (tested with explicit X, Y, Z values as well as map clicks).
Root cause analysis
Step 1 — Identifying the CeleryScript payload
We captured the exact payload the web app sends to the device for a simple move sequence (X:100, Y:100, Z:-10):
{
"kind": "move",
"args": {},
"body": [
{"kind": "axis_overwrite", "args": {"axis": "x", "axis_operand": {"kind": "numeric", "args": {"number": 100}}}},
{"kind": "axis_overwrite", "args": {"axis": "y", "axis_operand": {"kind": "numeric", "args": {"number": 100}}}},
{"kind": "axis_overwrite", "args": {"axis": "z", "axis_operand": {"kind": "numeric", "args": {"number": -10}}}}
]
}
The payload is valid — all three axes are explicitly provided with numeric values.
Step 2 — Locating the crash
In lib/celery/compilers/move_compiler.ex, the add_defaults/1 function reads default_axis_order from fbos_config:
defp add_defaults(body) do
if Enum.any?(body, fn %{kind: k} -> k == :axis_order end) do
body
else
default_order = default_axis_order() # <-- returns nil on self-hosted
case default_order do
"safe_z" ->
body ++ [%{kind: :safe_z, args: %{}}]
_ ->
[grouping, route] = String.split(default_order, ";") # <-- CRASH: nil passed here
body ++ [%{kind: :axis_order, args: %{grouping: grouping, route: route}}]
end
end
end
When default_axis_order is nil (which it is on self-hosted installations where the database column does not exist), String.split(nil, ";") raises a FunctionClauseError because String.split/3 does not accept nil as its first argument.
Step 3 — Confirming the missing column
The fbos_configs table on a self-hosted installation does not have a default_axis_order column — it was never added by a web app migration. Confirmed via Rails console:
ActiveRecord::Base.connection.columns("fbos_configs").map(&:name)
# => ["id", "device_id", ..., "safe_height", "soil_height", "gantry_height"]
# default_axis_order is absent
As a result, FarmbotOS.Asset.fbos_config(:default_axis_order) returns nil, and the crash follows.
Step 4 — Workaround applied
We manually added the missing column directly in the database and broadcast the updated config to the device:
ActiveRecord::Base.connection.add_column :fbos_configs, :default_axis_order, :string, default: "xyz;in_order"
FbosConfig.reset_column_information
Device.first.fbos_config.broadcast!
After the device received the updated config, move commands started working immediately:
device_1 FBOS_LOG v15.5.1 Moving to (1340, 760, 0)
Suggested fix
Option A — Fix in FBOS (defensive nil guard)
In lib/celery/compilers/move_compiler.ex, add a fallback for when default_axis_order is nil:
[grouping, route] = String.split(default_order || "xyz;in_order", ";")
This is a one-line fix that makes FBOS resilient to missing or nil config values, which is important for self-hosted users who may not always have the latest database schema.
Option B — Fix in farmbot-web-app (add migration)
Add a Rails migration to the web app that creates the default_axis_order column with a sensible default:
class AddDefaultAxisOrderToFbosConfigs < ActiveRecord::Migration[6.1]
def change
add_column :fbos_configs, :default_axis_order, :string, default: "xyz;in_order"
end
end
And include the field in the FbosConfig serializer so it is broadcast to the device on sync.
Recommended: both options together
Option A protects against future cases where the config value is missing or nil. Option B ensures self-hosted users get the correct value from the server. Both together provide the most robust solution.
The bug was introduced in commit 573bd63e ([v15.5.0-rc5] use axis_order default setting, 2025-08-02) when default_axis_order was read from fbos_config without a nil fallback, and without a corresponding web app migration to guarantee the value is always present.
Happy to provide any additional logs or test data. Thank you for your work on FarmBot OS!