gofiber/fiber · error
failed to open
Error message
failed to open: %w
What it means
Returned by the internal readContent helper when os.Open fails on the named file. readContent is used by Ctx.Render (res.go:938) to load a template file when no template engine is configured (raw html/template rendering). The error wraps the OS error: 'failed to open: open foo.tmpl: no such file or directory'.
Solutions
- Use an absolute path or embed templates with go:embed so the path is stable regardless of cwd.
- Confirm the binary's working directory at runtime (log os.Getwd) and resolve template roots from it.
- Set Views with fiber's html engine so engine-relative template names are used instead of raw file paths.
- Verify deploy artifacts include the template files (check the Docker image / CI output).
Example fix
// before
app.Get("/", func(c fiber.Ctx) error {
return c.Render("templates/home.tmpl", fiber.Map{})
})
// after
//go:embed templates/*
var tmplFS embed.FS
engine := html.NewFileSystem(http.FS(tmplFS), ".tmpl")
app := fiber.New(fiber.Config{Views: engine}) Defensive patterns
Strategy: validation
Validate before calling
// ensure the template path resolves before rendering
abs, err := filepath.Abs(name)
if err != nil {
return err
}
if _, err := os.Stat(abs); err != nil {
return fiber.NewError(fiber.StatusNotFound, "template not found")
} Type guard
null
Try / catch
if err := c.Render(name, bind); err != nil {
if strings.Contains(err.Error(), "failed to open") {
return fiber.NewError(fiber.StatusNotFound, "template not found")
}
return err
} Prevention
- Embed templates with go:embed so paths are filesystem-independent.
- Use fiber's html engine with Views set so engine-relative names are resolved consistently.
- Log os.Getwd at startup to know what relative paths resolve against.
- Confirm the deploy image includes the template files.
When it happens
Trigger: Calling c.Render("views/missing.tmpl", bind) with no Views/engine set, or any code path routing through readContent where the file path does not resolve to a readable file.
Common situations: Wrong working directory (relative path resolved against the process cwd, not the source file), template path typo, file not deployed in the container image, restrictive file permissions, or rendering a path built from user input that does not exist.
Related errors
- failed to read
- failed to listen
- parse constraint arg
- tls: cannot load TLS key pair from certFile=
- %w: %q: %w
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/8ba148d850763c62.
Report an issue: GitHub.
Appendix: source
Thrown at helpers.go:158
value := reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem() //nolint:gosec // Access to unexported field is required for listeners that don't expose TLS config methods.
if !value.IsValid() {
return nil
}
cfg, ok := value.Interface().(*tls.Config)
if !ok {
return nil
}
return cfg
}
// readContent opens a named file and read content from it
func readContent(rf io.ReaderFrom, name string) (int64, error) {
// Read file
f, err := os.Open(filepath.Clean(name))
if err != nil {
return 0, fmt.Errorf("failed to open: %w", err)
}
defer func() {
if err = f.Close(); err != nil {
log.Errorf("Error closing file: %s", err)
}
}()
n, readErr := rf.ReadFrom(f)
if readErr != nil {
return n, fmt.Errorf("failed to read: %w", readErr)
}
return n, nil
}
// quoteEscapeMask marks the lanes of w holding bytes quoteRawString must
// escape: '\\', '"', any C0 control (including HTAB), or DEL. Lanes >= 0x80
// are never marked; non-ASCII bytes pass through verbatim. This is
// utils.IndexNonQuotable's RFC 9110 set widened by HTAB, which the RFC
// permits as qdtext but this function has always percent-encoded.View on GitHub (pinned to a105acad6c)