When it refuses to start
Past the plain config errors (a YAML typo, a port out of range), it refuses to start for five reasons, all on purpose. Every one prints the fix instead of a stack trace, because whoever reads it is staring at a CrashLoopBackOff and doesn’t need my Go paths.
| Refusal | Fix |
|---|---|
| Authentication is disabled | Configure a user. Or, if the network really is isolated and you’ve decided to own that, set HOTLOOP_FLOW_INSECURE=true in the environment. auth.enabled: false in the file isn’t enough on its own. (Up to and including 2.0.4 the variable did nothing and you got this refusal back regardless. Fixed in 2.0.5.) |
| Authentication is on with no users | Set auth.users, or HOTLOOP_FLOW_ADMIN_USER and HOTLOOP_FLOW_ADMIN_PASSWORD_HASH. |
A passwordHash that is not bcrypt |
Run hotloop-flow hash-password. This check exists so a plaintext password can never end up in a ConfigMap by accident. |
| No credential secret | Set HOTLOOP_FLOW_CREDENTIAL_SECRET. Or HOTLOOP_FLOW_ALLOW_PLAINTEXT_CREDENTIALS=true if this instance holds no secrets at all. |
discovery or exec enabled with an empty allowlist |
List what is permitted, or turn the thing off. An empty allowlist read permissively is exactly how a narrow capability becomes a shell. |
What it will not refuse to start over is one bad node. A flow with a single
broken node runs every other node and logs the failure, because taking a line
down over one typo in one dialog is worse than running 40 nodes out of 41 and
saying so. Same with an exec allowlist that names something not on the PATH
yet: it warns at boot and resolves it again when a flow uses it, since an init
container or a mounted volume can legitimately bring it in after start-up.
If the flow file won’t parse, it tries the backups newest first, keeps the
corrupt file next to it as .corrupt, and logs exactly which backup it fell
back to. If none of them parse either, it stops there, rather than come up empty
and look healthy while every flow you had is gone. And a deploy writes the flow
file before it stops the old runtime, so if the save fails, your previous
flows keep running instead of the line going down over a bad save. That order is
not the obvious one, it is not an accident, and a test fails if anybody swaps it.