{"id":"65492ed85b27d265","repo":"gofiber/fiber","slug":"cyclic-extractor-chain","errorCode":null,"errorMessage":"cyclic extractor chain","messagePattern":"cyclic extractor chain","errorType":"exception","errorClass":"ErrChainCycle","httpStatus":null,"severity":"error","filePath":"extractors/extractors.go","lineNumber":67,"sourceCode":"\n\t// SourceQuery indicates the value is extracted from URL query parameters.\n\tSourceQuery\n\n\t// SourceParam indicates the value is extracted from URL path parameters.\n\tSourceParam\n\n\t// SourceCookie indicates the value is extracted from cookies.\n\tSourceCookie\n\n\t// SourceCustom indicates the value is extracted using a custom extractor function.\n\tSourceCustom\n)\n\n// ErrNotFound is returned when the requested value is missing or empty.\nvar ErrNotFound = errors.New(\"value not found\")\n\n// ErrChainCycle is returned when a chain extractor recursively invokes itself.\nvar ErrChainCycle = errors.New(\"cyclic extractor chain\")\n\n// Extractor defines a value extraction method with metadata.\ntype Extractor struct {\n\tExtract    func(fiber.Ctx) (string, error)\n\tKey        string      // The parameter/header name used for extraction\n\tAuthScheme string      // The auth scheme used, e.g., \"Bearer\"\n\tChain      []Extractor // For chained extractors, stores all extractors in the chain\n\tSource     Source      // The type of source being extracted from\n}\n\n// Contains reports whether this extractor, or any extractor in its chain, matches pred.\n//\n// If pred is nil, Contains returns false.\nfunc (e Extractor) Contains(pred func(Extractor) bool) bool {\n\tif pred == nil {\n\t\treturn false\n\t}\n","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/extractors/extractors.go#L49-L85","documentation":"ErrChainCycle ('cyclic extractor chain', extractors/extractors.go:67) is returned by Chain().Extract (extractors.go:524) when the chain re-enters itself on the same request context. Chain uses a per-chain Locals guard key (set true on entry, cleared on exit); if Extract is invoked again while active, the guard detects the re-entry and short-circuits to prevent infinite recursion.","triggerScenarios":"An extractor in a Chain whose Extract function itself calls the same Chain's Extract on the same fiber.Ctx (e.g. a FromCustom function that resolves to the outer chain), or two chains referencing each other transitively. A misbehaving custom extractor that re-dispatches through the parent chain triggers the guard.","commonSituations":"Building recursive extractor graphs by mistake, or a custom extractor that 'falls back' to the parent chain instead of to a primitive source. Refactoring that accidentally wires a chain into itself.","solutions":["Ensure each extractor in a Chain resolves to a primitive source (header/cookie/query/form/param) or a distinct custom function, never back to the same chain.","Factor the shared extraction logic into a standalone function and have both call it, rather than chaining the chain into itself.","Add a unit test that calls the chain's Extract twice in sequence to confirm no self-reference exists."],"exampleFix":"// before\nchain := extractors.Chain()\nchain = extractors.Chain(\n    extractors.FromCustom(\"x\", func(c fiber.Ctx) (string, error) {\n        return chain.Extract(c) // re-enters itself -> ErrChainCycle\n    }),\n)\n\n// after\ninner := extractors.FromHeader(\"X-API-Key\")\nchain := extractors.Chain(\n    inner,\n    extractors.FromCookie(\"api_key\"),\n)","handlingStrategy":"validation","validationCode":"// Detect self-referential chains at construction time.\nif chain.Contains(func(e extractors.Extractor) bool {\n    return e.Extract == nil // placeholder for identity; extend as needed\n}) {\n    log.Println(\"warning: inspect chain for self-reference\")\n}","typeGuard":null,"tryCatchPattern":"v, err := chain.Extract(c)\nif errors.Is(err, extractors.ErrChainCycle) {\n    return fiber.NewError(fiber.StatusInternalServerError, \"extractor misconfigured (cycle)\")\n}","preventionTips":["Never have an extractor in a Chain call the same Chain's Extract.","Factor shared logic into a standalone primitive extractor instead of re-dispatching.","Add a test invoking the chain twice in sequence to catch accidental self-reference."],"tags":["extractors","chain","recursion","fiber"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}