Skip to content
GitHub

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.