vxcontrol/pentagi · critical
failed to load default templates: %w
Error message
failed to load default templates: %w
What it means
newUserPrompter calls templates.LoadDefaultPromptsMap() to read the default prompt templates from the embedded filesystem (go:embed "prompts"). Failure is wrapped as "failed to load default templates: %w". Under the hood the templates are read once (sync.Once) from the embedded FS; errors come from ReadDir/ReadFile on the embedded "prompts" directory and are cached, so once it fails it keeps failing for the process lifetime.
Source
Thrown at backend/pkg/controller/prompter.go:24
"pentagi/pkg/database"
"pentagi/pkg/templates"
)
// newUserPrompter loads the user's custom prompts from the database and
// overlays them onto the compiled default templates. Prompt types that
// the user has not customized continue to use the defaults. A database
// error is returned to the caller so that session creation fails
// explicitly instead of silently falling back to defaults.
func newUserPrompter(ctx context.Context, db database.Querier, userID int64) (templates.Prompter, error) {
userPrompts, err := db.GetUserPrompts(ctx, userID)
if err != nil {
return nil, fmt.Errorf("failed to load user prompts: %w", err)
}
defaults, err := templates.LoadDefaultPromptsMap()
if err != nil {
return nil, fmt.Errorf("failed to load default templates: %w", err)
}
return buildUserPrompter(defaults, userPrompts), nil
}
// buildUserPrompter is the pure merge step extracted from newUserPrompter so
// it can be unit-tested without a database fake or filesystem access. It
// mutates the supplied defaults map by overlaying each non-empty user
// override on top, then returns a Prompter backed by that map. Callers must
// pass a fresh map (e.g., from templates.LoadDefaultPromptsMap) so the
// embedded defaults are not modified.
func buildUserPrompter(defaults templates.PromptsMap, userPrompts []database.Prompt) templates.Prompter {
for _, p := range userPrompts {
if p.Prompt == "" {
// The Prompts UI uses delete (or reset, which writes the
// default body back) to remove a customization, so an empty
// body is unexpected. Skip it instead of clobbering the
// default with an empty string that would later surface asView on GitHub (pinned to ea665308ba)
Solutions
- Rebuild the backend binary from an intact source tree so the prompts directory is embedded correctly.
- Verify backend/pkg/templates/prompts exists and contains *.tmpl files, and that the go:embed directive matches.
- Note the error is cached in sync.Once — a restart will NOT clear it; only a correct binary will.
- If running a custom build pipeline, ensure it does not strip or mutate embedded assets.
Example fix
// before: prompts dir missing from the embed //go:embed prompts/*.tmpl // after: ensure files exist and embed whole directory //go:embed all:prompts
Defensive patterns
Strategy: validation
Validate before calling
// verify templates load before starting workers (run once at startup)
if _, err := templates.LoadDefaultPromptsMap(); err != nil {
log.Fatalf("embedded prompt templates broken: %v", err)
} Type guard
null
Try / catch
prompter, err := newUserPrompter(ctx, db, userID)
if err != nil {
if strings.Contains(err.Error(), "failed to load default templates") {
// cached in sync.Once — retrying in-process will NOT help; fail fast
return fmt.Errorf("binary is missing embedded templates, rebuild required: %w", err)
}
return err
} Prevention
- Smoke-test template loading at process startup, not on first worker creation.
- Never strip embedded assets in build/packaging pipelines (upx, resource strippers).
- Keep backend/pkg/templates/prompts and the go:embed directive intact.
- Remember sync.Once caches the failure — restarts don't fix a broken binary, only a rebuild does.
When it happens
Trigger: Creating or loading any flow/assistant worker when the embedded template FS read fails — realistically only a broken build/embed directive (prompts directory missing from the binary), since the templates are compiled in and not read from disk at runtime.
Common situations: Custom builds that removed or renamed the pkg/templates/prompts directory; build tooling that stripped embedded files; tampered or malformed binary after post-build processing (e.g. aggressive packing/upx or resource-stripping).
Related errors
- invalid PromptType: %s
- bearer scheme must be used
- token can't be empty
- token validation disabled with default salt
- token is invalid
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/584312f5bf3a0a8c.
Report an issue: GitHub.