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

  1. Use an absolute path or embed templates with go:embed so the path is stable regardless of cwd.
  2. Confirm the binary's working directory at runtime (log os.Getwd) and resolve template roots from it.
  3. Set Views with fiber's html engine so engine-relative template names are used instead of raw file paths.
  4. 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

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


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)