Billionmail/BillionMail · error
rspamdadm not found
Error message
rspamdadm not found
What it means
InitWorkerController runs `rspamadm pw` inside the Rspamd Docker container to hash a generated controller password. If the exec call returns a nil result (no command output object), the code treats it as rspamadm being unavailable and returns this error. It guards against silently writing an empty password hash into worker-controller.inc.
Source
Thrown at core/internal/service/rspamd/worker_controller.go:47
passwordPlain := grand.S(16)
// Generate the worker controller configuration
dk, err := docker.NewDockerAPI()
if err != nil {
return
}
defer dk.Close()
res, err := dk.ExecCommandByName(context.Background(), consts.SERVICES.Rspamd, []string{"rspamadm", "pw", "-p", passwordPlain}, "root")
if err != nil {
return
}
if res == nil {
err = errors.New("rspamdadm not found")
return
}
_, err = public.WriteFile(wci, `count = 1;
password = "`+strings.TrimSpace(strings.SplitN(strings.TrimSpace(res.Output), "\n", 2)[0])+`";
secure_ip = "127.0.0.1";
secure_ip = "::1";
static_dir = "${WWWDIR}";`)
if err != nil {
return
}
// Save the password
err = public.OptionsMgrInstance.SetOption(context.Background(), "rspamd_worker_controller_password", passwordPlain)
if err != nil {
returnView on GitHub (pinned to fc36c76c05)
Solutions
- Ensure the Rspamd container is running and healthy: docker ps | grep rspamd
- Verify rspamadm exists in the container: docker exec <rspamd> which rspamadm
- Re-run initialization after the container is up (the error path is transient in most deploys)
- Check docker API logs for the failed exec and why it returned no result
- As a last resort, recreate the Rspamd container from the official BillionMail image
Example fix
// before
res, err := dk.ExecCommandByName(ctx, consts.SERVICES.Rspamd, []string{"rspamadm", "pw", "-p", passwordPlain}, "root")
if err != nil { return }
// after
if err := waitForContainerHealthy(ctx, consts.SERVICES.Rspamd); err != nil { return err }
res, err := dk.ExecCommandByName(ctx, consts.SERVICES.Rspamd, []string{"rspamadm", "pw", "-p", passwordPlain}, "root")
if err != nil { return }
if res == nil { return errors.New("rspamadm not found") } Defensive patterns
Strategy: validation
Validate before calling
out, err := exec.Command("docker", "exec", rspamdContainer, "which", "rspamadm").Output()
if err != nil || len(out) == 0 {
return fmt.Errorf("rspamadm unavailable in container %s", rspamdContainer)
} Try / catch
if err := rspamd.InitWorkerController(); err != nil {
if strings.Contains(err.Error(), "rspamdadm not found") {
// wait for the rspamd container then retry once
time.Sleep(10 * time.Second)
return rspamd.InitWorkerController()
}
return err
} Prevention
- Ensure the official BillionMail rspamd image includes rspamadm (don't use stripped images)
- Add a container healthcheck gate before running rspamd initialization
- Log docker exec results (including nil-result cases) for diagnostics
- Run initialization only after the full mail stack is deployed
When it happens
Trigger: dk.ExecCommandByName succeeds without error but returns res == nil — e.g. the Rspamd container reported no result for the exec, the container is in a bad state, or the docker API returned an empty exec response.
Common situations: Rspamd container not fully started or restarting; rspamadm binary missing from the container image (unusual/minimal image); docker API proxy returning empty responses; running initialization before the mail stack is deployed.
Related errors
- Failed to generate DKIM key pair: %v
- failed to update BILLIONMAIL_HOSTNAME in postfix container:
- Failed to restart rspamd container: %v
- failed to restart rspamd container: %v
- failed to hash postfix config: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/951b71e0ffccbe73.
Report an issue: GitHub.