argoproj/argo-workflows · error
index template error (err.Error())
Error message
index template error (err.Error())
What it means
ServerFiles (server/static/static.go:56) serves the embedded UI index.html for '/' and for any path that is not a known UI asset (SPA fallback). It fails with 500 when getIndexData() cannot read ui/dist/app/index.html from the embedded filesystem, or cannot apply the base-href rewrite. Since the assets are embedded at build time, this almost always means the binary was built without the UI assets embedded (e.g. `make start UI=false` or a stripped/custom build) or the baseHRef rewrite produced invalid data.
Source
Thrown at server/static/static.go:56
if r.Method == http.MethodOptions { // Set CORS headers for preflight request
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
w.WriteHeader(http.StatusNoContent)
return
}
}
// `data:` is need for Monaco editors wiggly red lines
w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-inline'; img-src 'self' data:")
if s.hsts {
w.Header().Set("Strict-Transport-Security", "max-age=31536000")
}
if r.URL.Path == "/" || !s.uiAssetExists(r.URL.Path) {
data, err := s.getIndexData()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
modTime, err := time.Parse(argo.GetVersion().BuildDate, time.RFC3339)
if err != nil {
modTime = time.Now()
}
http.ServeContent(w, r, "index.html", modTime, bytes.NewReader(data))
} else {
staticFS, _ := fs.Sub(s.staticAssets, ui.EMBED_PATH)
http.FileServer(http.FS(staticFS)).ServeHTTP(w, r)
}
}
func (s *FilesServer) getIndexData() ([]byte, error) {
data, err := s.staticAssets.ReadFile(ui.EMBED_PATH + "/index.html")
if err != nil {
return data, errView on GitHub (pinned to 35bff19146)
Solutions
- Rebuild/redeploy argo-server with the UI included: build via `make cli` (or the official image) so ui/dist/app/index.html is embedded — a UI=false or stripped build cannot serve the UI
- If you intended an API-only server, use the gRPC/HTTP API or `argo` CLI instead of opening the UI URL
- If building a custom embed.FS, ensure it contains index.html under ui.EMBED_PATH before calling NewFilesServer
- Run `make ui` in the repo so ui/dist exists before compiling the embedded assets
Example fix
// before: binary built without UI -> 500 on / make start UI=false // after: build with UI assets embedded make cli && ./dist/argo server
Defensive patterns
Strategy: fallback
Validate before calling
// before serving, verify the UI assets are embedded in the binary
if _, err := staticAssets.ReadFile("ui/dist/app/index.html"); err != nil {
log.Fatal("argo-server built without UI assets; rebuild with `make cli` (not UI=false)")
} Type guard
func uiAssetsEmbedded(assets embed.FS) bool {
f, err := assets.Open("ui/dist/app/index.html")
if err != nil { return false }
f.Close()
return true
} Try / catch
// server-side fallback when index data is unavailable
if _, err := s.getIndexData(); err != nil {
http.Error(w, "UI not built into this binary; use the argo CLI or gRPC API", http.StatusServiceUnavailable)
return
} Prevention
- Never deploy a UI=false or asset-stripped binary where users will open the web UI
- Build with the repo's own Makefile targets (`make cli`, `make controller`) so `ui/dist` is generated and embedded
- In custom builds, run `make ui` before `go build` so the embed directory is populated
- Smoke-test GET / on argo-server after each deployment to catch missing-asset builds immediately
When it happens
Trigger: Requesting the UI root path '/' (or any unknown path hitting the SPA fallback) against an argo-server binary built without the embedded UI assets (ui/dist/app/index.html missing from the embed.FS); or a custom staticAssets FS passed to NewFilesServer that lacks index.html.
Common situations: Running argo-server built with UI=false for lightweight/API-only use and then browsing to the server URL; custom Docker builds that skip the UI asset build step; running the binary from a directory-based build where `ui/dist` was never built (`make ui` skipped); custom baseHRef flags with a hand-crafted embed FS.
Related errors
- Should specify a node when we get archived logs
- no artifact logs are available
- cron schedules must consist of 5 values only
- cron schedules must consist of 5 values only
- failed to stream artifact: %v
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/a426b4ae8cc6c941.
Report an issue: GitHub.