gofiber/fiber · error · UnknownTagError

ErrUnknownTag

ErrUnknownTag

Error message

logger: unknown template tag

What it means

logger.New compiles Config.Format into a chain of tag renderers via logtemplate.Build; if the format references a tag that has no registered renderer (e.g. ${typo} or ${reqHeader:} with an empty param), Build returns an UnknownTagError. translateBuildError converts it to the public logger.UnknownTagError (which wraps ErrUnknownTag), and logger.New panics with that typed error so the misconfiguration surfaces at startup rather than producing a silently-empty log field. The panic value supports errors.Is(err, ErrUnknownTag) and errors.As for *UnknownTagError.

Source

Thrown at middleware/logger/logger.go:84

		dataPool = sync.Pool{New: func() any { return new(Data) }}
	)

	// Err padding starts at the documented default and grows once on first
	// request to fit the longest registered route path.
	errPadding := defaultErrPadding
	errPaddingStr := strconv.Itoa(errPadding)

	// Before handling func
	cfg.BeforeHandlerFunc(&cfg)

	// Logger data
	// instead of analyzing the template inside(handler) each time, this is done once before
	// and we create several slices of the same length with the functions to be executed and fixed parts.
	template, err := logtemplate.Build[fiber.Ctx, Data](cfg.Format, createTagMap(&cfg))
	if err != nil {
		if translated := translateBuildError(err); translated != nil {
			panic(translated)
		}
		panic(err)
	}
	templateChain, logFuncChain := template.Chains()

	// Return new handler
	return func(c fiber.Ctx) error {
		// Don't execute middleware if Next returns true
		if cfg.Next != nil && cfg.Next(c) {
			return c.Next()
		}

		// Set error handler once
		once.Do(func() {
			// get longest possible path
			stack := c.App().Stack()
			for m := range stack {
				for r := range stack[m] {

View on GitHub (pinned to a105acad6c)

Solutions

  1. Correct the tag name — cross-check against the Tag* constants in middleware/logger/tags.go (e.g. ${referer}, ${status}, ${method}, ${ip}, ${latency}).
  2. Register any custom tag with logger.MustRegisterTag BEFORE logger.New(...) compiles the format.
  3. Recover the typed error to introspect which tag failed: use errors.As(err, &unknownTagErr) and read unknownTagErr.Tag / unknownTagErr.Hint.

Example fix

// before — 'referer' misspelled
app.Use(logger.New(logger.Config{
    Format: "${time} ${method} ${path} ${refererr}\n",
}))

// after
app.Use(logger.New(logger.Config{
    Format: "${time} ${method} ${path} ${referer}\n",
}))
Defensive patterns

Strategy: validation

Validate before calling

// Validate the format compiles before logger.New panics at boot.
// Easiest: boot the app in a test.
func TestLoggerFormatCompiles(t *testing.T) {
    t.Parallel()
    assert.NotPanics(t, func() {
        app := fiber.New()
        app.Use(logger.New(logger.Config{Format: yourFormat}))
        _ = app
    })
}

Type guard

func referencesKnownTags(format string, known map[string]struct{}) (missing []string) {
    for _, m := range tagRegexp.FindAllStringSubmatch(format, -1) {
        if _, ok := known[m[1]]; !ok {
            missing = append(missing, m[1])
        }
    }
    return
}

Try / catch

// If you must isolate the failure (e.g. plugin host), recover the typed error:
defer func() {
    if r := recover(); r != nil {
        var ute *logger.UnknownTagError
        if errors.As(r.(error), &ute) {
            log.Printf("logger format references unknown tag %q (hint: %s)", ute.Tag, ute.Hint)
        }
        panic(r) // re-panic otherwise
    }
}()
app.Use(logger.New(logger.Config{Format: fmtStr}))

Prevention

When it happens

Trigger: Config.Format containing ${nonexistent}, a misspelled built-in tag like ${referer} (the constant is TagReferer, no second 'r'), or a parametric tag (${query:}) with an empty/invalid parameter. Custom tags referenced before MustRegisterTag runs also hit this.

Common situations: Typo in the format string; referencing a context tag (e.g. ${api-key}) before the producing middleware registered it; upgrading Fiber and hitting a renamed/removed tag; copy-pasting a format from an older version.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/058f4fd661925799. Report an issue: GitHub.