{"record":{"id":"abc7917f6b8687d8","repo":"kataras/iris","slug":"accesslog-setformatter-called-with-nil-writer","errorCode":null,"errorMessage":"accesslog: SetFormatter called with nil Writer","messagePattern":"accesslog: SetFormatter called with nil Writer","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/accesslog/accesslog.go","lineNumber":672,"sourceCode":"\t\t\t\terr = fmt.Errorf(\"%v, %v\", err, tErr)\n\t\t\t}\n\t\t}\n\t}\n\tac.mu.Unlock()\n\n\treturn err\n}\n\n// SetFormatter sets a custom formatter to print the logs.\n// Any custom output writers should be\n// already registered before calling this method.\n// Returns this AccessLog instance.\n//\n// Usage:\n// ac.SetFormatter(&accesslog.JSON{Indent: \"    \"})\nfunc (ac *AccessLog) SetFormatter(f Formatter) *AccessLog {\n\tif ac.Writer == nil {\n\t\tpanic(\"accesslog: SetFormatter called with nil Writer\")\n\t}\n\n\tif f == nil {\n\t\treturn ac\n\t}\n\n\tif flusher, ok := ac.formatter.(Flusher); ok {\n\t\t// PREPEND formatter flushes, they should run before destination's ones.\n\t\tac.Flushers = append([]Flusher{flusher}, ac.Flushers...)\n\t}\n\n\t// Inject the writer (AccessLog) here, the writer\n\t// is protected with mutex.\n\tf.SetOutput(ac)\n\n\tac.formatter = f\n\treturn ac\n}","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/kataras/iris/blob/7bedaf55a0b64bbb2248a5845a2c60d81a30996a/middleware/accesslog/accesslog.go#L654-L690","documentation":"AccessLog.SetFormatter panics immediately if the AccessLog's Writer field is nil (middleware/accesslog/accesslog.go:672), because a formatter has nowhere to write output. The check runs before the formatter is even inspected.","triggerScenarios":"Creating an AccessLog struct manually (not via accesslog.New, which requires a writer) with Writer left nil and then calling ac.SetFormatter(&accesslog.JSON{...}).","commonSituations":"Constructing &accesslog.AccessLog{} directly and setting fields piecemeal; assigning a nil writer variable by mistake; reordering initialization so SetFormatter runs before Writer is set.","solutions":["Initialize the AccessLog with accesslog.New(io.Writer) so Writer is always set.","Set ac.Writer to a valid io.Writer (e.g. an *os.File) before calling SetFormatter.","Reorder code so SetFormatter is called after Writer assignment when building AccessLog manually."],"exampleFix":"// before\nac := &accesslog.AccessLog{}\nac.SetFormatter(&accesslog.JSON{}) // panics: nil Writer\n\n// after\nf := accesslog.File(\"./access.log\")\nac := accesslog.New(f)\nac.SetFormatter(&accesslog.JSON{})","handlingStrategy":"validation","validationCode":"// Guard before calling SetFormatter\nif ac.Writer == nil {\n    return errors.New(\"accesslog writer not initialized\")\n}\nac.SetFormatter(&accesslog.JSON{})","typeGuard":"func writerSet(ac *accesslog.AccessLog) bool {\n    return ac != nil && ac.Writer != nil\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        log.Fatalf(\"SetFormatter: %v\", r)\n    }\n}()","preventionTips":["Always build AccessLog via accesslog.New(writer), never as a bare struct literal.","Set Writer before any formatter configuration in initialization code.","Add an init-time assertion that ac.Writer != nil."],"tags":["go","panic","logging","nil-pointer"],"backgroundTag":"nil-writer","analyzedSha":"7bedaf55a0b64bbb2248a5845a2c60d81a30996a","analyzedAt":"2026-08-30T20:38:16.250Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}