evanw/esbuild · error
The service was stopped
Error message
The service was stopped
What it means
Returned from the OnEnd plugin callback registered in cmd/esbuild/service.go:746. The Go-side bridge calls service.sendRequest to forward the on-end event to the (separate, JS-driven) esbuild service and type-asserts the reply to map[string]interface{}. If the assertion fails it means sendRequest did not receive a well-formed response — the service process has been disposed, crashed, or its packet stream is broken — so the callback returns errors.New("The service was stopped").
Solutions
- Treat this as a terminal condition for the context: do not issue further build calls on it; create a new context instead.
- Ensure dispose() is not called concurrently with an in-flight build, or expect OnEnd to surface this error and handle it gracefully.
- If the service is crashing unexpectedly, capture stderr/logs from the esbuild subprocess to find the root cause (OOM, panic).
Example fix
// before (ignoring the stopped error, then reusing the dead context)
result := ctx.Rebuild()
// later: ctx.Dispose() fires OnEnd with "The service was stopped"
ctx.Rebuild() // hangs/fails
// after (treat stopped as terminal, recreate context)
result, err := ctx.Rebuild()
if err != nil && err.Error() == "The service was stopped" {
ctx.Dispose()
ctx = newContext() // fresh esbuild context
} Defensive patterns
Strategy: try-catch
Validate before calling
// No pre-call validation can fully prevent this; instead, ensure the service is alive
func serviceAlive(svc *serviceType) bool {
svc.mutex.Lock(); defer svc.mutex.Unlock()
return !svc.isDisposed // (conceptual) check the lifecycle flag before issuing requests
} Try / catch
result, err := ctx.Rebuild()
if err != nil && err.Error() == "The service was stopped" {
ctx.Dispose()
ctx, _ = api.Context(opts) // recreate; the old context is terminal
result, err = ctx.Rebuild()
} Prevention
- Do not call dispose() while a build is in flight; coordinate teardown with build completion.
- Treat 'The service was stopped' as terminal for that context — never reuse it.
- Capture esbuild subprocess stderr to diagnose unexpected (non-dispose) stops like OOM or panics.
When it happens
Trigger: Calling dispose() on a build context (or the underlying esbuild service process exiting/crashing) while an OnEnd callback is mid-flight. The reply channel either yields nil or a non-map value, so the type assertion `.(map[string]interface{})` returns ok=false.
Common situations: A long-running watch/rebuild context is disposed while a build is in progress; the service subprocess is killed by the OS or OOM; or a host application tears down esbuild on shutdown while plugin callbacks are still running.
Related errors
- Invalid path suffix returned from plugin (must start with…
- [ ] filter is not a valid Go regular expression
- [ ] is missing a filter
- Cannot compute relative path from
- Cannot serve a disposed context
AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09).
Data as JSON: /api/errors/602737caabe28e69.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/esbuild/service.go:746
//
// This is especially important if "write" is false since otherwise
// we'd unnecessarily send the entire contents of all output files!
//
// "If a tree falls in a forest and no one is
// around to hear it, does it make a sound?"
//
activeBuild.mutex.Lock()
isWithinRebuild := activeBuild.withinRebuildCount > 0
activeBuild.mutex.Unlock()
if !hasOnEndCallbacks && !isWithinRebuild && !writeToStdout {
return api.OnEndResult{}, nil
}
request := resultToResponse(*result)
request["command"] = "on-end"
request["key"] = key
response, ok := service.sendRequest(request).(map[string]interface{})
if !ok {
return api.OnEndResult{}, errors.New("The service was stopped")
}
var errors []api.Message
var warnings []api.Message
if value, ok := response["errors"].([]interface{}); ok {
errors = decodeMessages(value)
}
if value, ok := response["warnings"].([]interface{}); ok {
warnings = decodeMessages(value)
}
return api.OnEndResult{
Errors: errors,
Warnings: warnings,
}, nil
})
},
})
ctx, err := api.Context(options)View on GitHub (pinned to f6058f8364)