Skip to content
Ironflow is pre-1.0: APIs can change between releases. Pin a version. What is ready →

Ironflow v0.53.0

Ironflow v0.53.0 fsyncs JetStream on every write, so a crash or power loss cannot roll back an acknowledged write. Runs get slower as a result. An assistant can now list failed runs over MCP, and a failed invoke child now fails its parent run instead of looping. Read the breaking changes before you upgrade: 3 items need action.

  • JetStream fsyncs every write before it acknowledges it — The nats-server default acknowledged at once and fsynced every two minutes, so an OS crash or power loss could roll back secrets, config, user KV, cron and debounce state, and pub/sub publishes. The embedded server now sets sync_interval: always, and so do the Docker Compose files and the Helm chart. A 10-step push run went from 6.2 ms to 17.9 ms on SQLite in a Linux VM. Outbox delivery stays near 610 events/s per node in the VM and drops from about 620 to 160-200 events/s on macOS. spec.nats.syncInterval, --nats-sync-interval and NATS_SYNC_INTERVAL take always or a positive Go duration; any other value stops serve. Upgrading: for the old throughput, set --nats-sync-interval=1s or longer and accept that window of loss. With external NATS (--nats-url), add sync_interval: always to the jetstream block of each NATS server yourself (ADR 0134, #3205)
  • emit, invoke, stream append, topic publish and event upcast read stdin only for --data-file - — An open pipe from an agent harness, a CI step or ssh used to hang these commands, and an explicit --data failed with “cannot combine multiple data sources”. Without the flag, a pipe is now ignored with a note on stderr, and a non-empty file redirected to stdin fails instead of sending {}. Upgrading: change ... | ironflow emit x to ... | ironflow emit x --data-file -, and ironflow emit x < payload.json to ironflow emit x --data-file payload.json (#3201)
  • An invalid yield from a pull worker fails the run with YIELD_REJECTED — The REST update answered 500 and left the run running with its lease held, so a worker that retried the 500 looped. It now fails the run without a retry, releases the lease and answers 400 invalid_argument. The streaming worker fails the run the same way. A sleep or waitForEvent yield with an empty step_id is now an invalid yield in push and pull mode. A store error still answers 500 and keeps the lease (#3203)
  • Filters on the MCP tool ironflow_list_runs — status (comma-separated, such as failed,paused), function_id, search (pattern match on the run ID), event_id, since and until (RFC3339) reach the server, so an assistant can list the failed runs. An unknown status, a bad timestamp, a non-string value or a window where until is not after since is refused before any request is sent (#3214, #3215)
  • A failed or timed-out invoke child reaches its parent in push mode — The push executor sent only completed steps, so the parent yielded the invoke again in a hot loop and stayed waiting. Push now sends the failed invoke step, as pull and streaming do, and its error is the error object as a JSON string. The Go and Python push handlers decode it, so InvokeError carries the child run ID and cause. A failed invokeAsync, such as an unknown target function, now raises InvokeError in push mode too (#3206)
  • Go SDK: a failed Invoke child fails the parent run at once — IsRetryable treated *InvokeError as retryable, so the parent sat waiting between retries and then paused. *InvokeError, including an invoke timeout, is now non-retryable with code INVOKE_FAILED in push, pull and streaming mode, as in the Node and Python SDKs. The parent’s compensations run at once (#3185)
  • A run whose resumes make no progress fails with RESUME_NO_PROGRESS — A worker that kept yielding a step the engine had already finished looped at full speed. The run now fails after 10 consecutive resumes from the same step. An operator resume sets the count to zero (#3208)
  • A repeated yield of a completed sleep or wait step no longer restarts it — The engine keeps the stored step result and resumes the run. A fenced wait re-yield no longer sets the completed step back to waiting (#3212)
  • Run search on SQLite treats \ as the escape character — \% and \_ in a ListRuns search match a literal % or _ on SQLite and PostgreSQL. Before, run\_01 found nothing on SQLite (#3216)
  • MCP list tools report bad paging as invalid_argument — A bad limit or offset reported unknown. A null limit or offset now counts as omitted (#3214)