{"record":{"id":"4273c3cebcdbb438","repo":"gofiber/fiber","slug":"logger-unknown-template-tag","errorCode":null,"errorMessage":"logger: unknown template tag","messagePattern":"logger: unknown template tag","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/logger/errors.go","lineNumber":12,"sourceCode":"package logger\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/gofiber/fiber/v3/internal/logtemplate\"\n)\n\n// ErrUnknownTag indicates that the logger middleware was configured with a\n// format that references a tag with no registered renderer.\nvar ErrUnknownTag = errors.New(\"logger: unknown template tag\")\n\n// UnknownTagError is the typed error panicked from New when Config.Format\n// references an unknown tag. Tag is the offending tag including any\n// parametric suffix; Param is the parameter portion when the tag was\n// parametric (empty for bare tags); Hint, when non-empty, is a human-\n// readable suggestion (e.g. parametric form for a likely-mistyped bare tag).\ntype UnknownTagError struct {\n\tTag   string\n\tParam string\n\tHint  string\n}\n\nfunc (e *UnknownTagError) Error() string {\n\tmsg := ErrUnknownTag.Error() + \": \" + strconv.Quote(e.Tag)\n\tif e.Hint != \"\" {\n\t\tmsg += \" (\" + e.Hint + \")\"\n\t}\n\treturn msg","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/logger/errors.go#L1-L30","documentation":"Returned (wrapped in UnknownTagError) by middleware/logger.New when the configured Config.Format references a template tag with no registered renderer. The typed UnknownTagError carries Tag, Param, and a Hint; its Unwrap returns ErrUnknownTag so errors.Is works. Construction fails at New so a misconfigured logger never starts serving.","triggerScenarios":"Calling logger.New with a Format string containing a ${tag} (or ${tag:param}) for a tag that is neither a built-in logger tag nor registered via logger.RegisterTag nor supplied in Config.CustomTags.","commonSituations":"Typo in a tag name (e.g. ${stats} instead of ${status}); referencing a tag from a newer/older version; using a parametric tag without the param suffix the renderer expects; copy-pasting a format from another app without registering its custom tags.","solutions":["Fix the typo: consult the tag constants in middleware/logger/tags.go for valid names.","Register the custom tag with logger.RegisterTag before calling logger.New, or pass it via Config.CustomTags.","If the error includes a Hint, follow it (e.g. a bare tag may need a ':param' suffix).","Use logger.MustRegisterTag only during init, not per-request."],"exampleFix":"// before\nlogger.New(logger.Config{Format: \"${stats}\"}) // typo\n// after\nlogger.New(logger.Config{Format: \"${status}\"})","handlingStrategy":"validation","validationCode":"func validateFormat(format string, custom map[string]logger.LogFunc) error {\n    // call logger.New in a recover, or maintain a set of valid tag names\n    // from middleware/logger/tags.go and check Format references before starting.\n    return nil\n}","typeGuard":null,"tryCatchPattern":"h, err := logger.New(cfg)\nif err != nil {\n    var ute *logger.UnknownTagError\n    if errors.As(err, &ute) {\n        // fix ute.Tag in cfg.Format, or register ute.Tag via RegisterTag/CustomTags\n    }\n    return err\n}","preventionTips":["Cross-check tag names against the constants in middleware/logger/tags.go.","Register custom tags in init before logger.New.","Use Config.CustomTags for per-instance tags rather than mutating global state."],"tags":["logger","config","template"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}