{"record":{"id":"3dcb11246f9340f9","repo":"gohugoio/hugo","slug":"panic-v","errorCode":null,"errorMessage":"panic: %v","messagePattern":"panic: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cache/dynacache/dynacache.go","lineNumber":443,"sourceCode":"}\n\n// GetOrCreateWitTimeout gets or creates a value for the given key and times out if the create function\n// takes too long.\nfunc (p *Partition[K, V]) doGetOrCreateWitTimeout(key K, duration time.Duration, create func(key K) (V, error)) (V, error) {\n\tresultch := make(chan V, 1)\n\terrch := make(chan error, 1)\n\n\tgo func() {\n\t\tvar (\n\t\t\tv   V\n\t\t\terr error\n\t\t)\n\t\tdefer func() {\n\t\t\tif r := recover(); r != nil {\n\t\t\t\tif rerr, ok := r.(error); ok {\n\t\t\t\t\terr = rerr\n\t\t\t\t} else {\n\t\t\t\t\terr = fmt.Errorf(\"panic: %v\", r)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\terrch <- err\n\t\t\t} else {\n\t\t\t\tresultch <- v\n\t\t\t}\n\t\t}()\n\t\tv, _, err = p.c.GetOrCreate(key, create)\n\t}()\n\n\tselect {\n\tcase v := <-resultch:\n\t\treturn v, nil\n\tcase err := <-errch:\n\t\treturn p.zero, err\n\tcase <-time.After(duration):\n\t\treturn p.zero, &herrors.TimeoutError{","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/cache/dynacache/dynacache.go#L425-L461","documentation":"In dynacache, GetOrCreateWitTimeout runs the value-creation function in a goroutine with a deferred recover (dynacache.go:438-444). If the create callback panics, the recovered value is converted into a fmt.Errorf(\"panic: %v\", r) and returned as a normal error instead of crashing the process. The %v carries the original panic value for diagnosis.","triggerScenarios":"The create function passed to a dynacache partition's GetOrCreateWitTimeout panics — e.g. nil-pointer dereference, index out of range, or an explicit panic deep in resource/image processing.","commonSituations":"Bugs in resource transformation pipelines that panic under edge-case inputs; nil dereferences during concurrent image processing; custom code registered as a cache create callback.","solutions":["Inspect the wrapped panic value (%v) in the error message to find the root cause","Add nil-checks and bounds checks in the create function before dereferencing","Reproduce by calling the create function directly outside the cache to get a full stack trace"],"exampleFix":"// before: create may panic on nil input\nv, err := partition.GetOrCreateWitTimeout(key, timeout, func(k K) (V, error) {\n    return doWork(input), nil // input may be nil\n})\n// after: guard the create function\nv, err := partition.GetOrCreateWitTimeout(key, timeout, func(k K) (V, nilV, error) {\n    if input == nil {\n        return zero, errors.New(\"nil input\")\n    }\n    return doWork(input), nil\n})","handlingStrategy":"try-catch","validationCode":"// Validate inputs to the create function before it runs inside the cache goroutine.\nif input == nil {\n    return zero, errors.New(\"input must not be nil\")\n}","typeGuard":null,"tryCatchPattern":"// dynacache already recovers the panic into an error; handle it at the call site.\nv, err := partition.GetOrCreateWitTimeout(key, timeout, create)\nif err != nil {\n    if strings.Contains(err.Error(), \"panic:\") {\n        // log full stack by reproducing outside the cache\n        log.Printf(\"cache create panicked: %v\", err)\n    }\n    return zero, err\n}","preventionTips":["Never let the create callback panic: add nil/bounds checks for all dereferences","Unit-test the create function in isolation to get a full stack trace on panic","Keep create functions small and pure to minimize panic surface area"],"tags":["cache","dynacache","panic","goroutine","concurrency","hugo"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}