gofiber/fiber · error · ErrChainCycle
cyclic extractor chain
Error message
cyclic extractor chain
What it means
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.
Source
Thrown at extractors/extractors.go:67
// SourceQuery indicates the value is extracted from URL query parameters.
SourceQuery
// SourceParam indicates the value is extracted from URL path parameters.
SourceParam
// SourceCookie indicates the value is extracted from cookies.
SourceCookie
// SourceCustom indicates the value is extracted using a custom extractor function.
SourceCustom
)
// ErrNotFound is returned when the requested value is missing or empty.
var ErrNotFound = errors.New("value not found")
// ErrChainCycle is returned when a chain extractor recursively invokes itself.
var ErrChainCycle = errors.New("cyclic extractor chain")
// Extractor defines a value extraction method with metadata.
type Extractor struct {
Extract func(fiber.Ctx) (string, error)
Key string // The parameter/header name used for extraction
AuthScheme string // The auth scheme used, e.g., "Bearer"
Chain []Extractor // For chained extractors, stores all extractors in the chain
Source Source // The type of source being extracted from
}
// Contains reports whether this extractor, or any extractor in its chain, matches pred.
//
// If pred is nil, Contains returns false.
func (e Extractor) Contains(pred func(Extractor) bool) bool {
if pred == nil {
return false
}
View on GitHub (pinned to 9a4c7e57fe)
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.
Example fix
// before
chain := extractors.Chain()
chain = extractors.Chain(
extractors.FromCustom("x", func(c fiber.Ctx) (string, error) {
return chain.Extract(c) // re-enters itself -> ErrChainCycle
}),
)
// after
inner := extractors.FromHeader("X-API-Key")
chain := extractors.Chain(
inner,
extractors.FromCookie("api_key"),
) Defensive patterns
Strategy: validation
Validate before calling
// Detect self-referential chains at construction time.
if chain.Contains(func(e extractors.Extractor) bool {
return e.Extract == nil // placeholder for identity; extend as needed
}) {
log.Println("warning: inspect chain for self-reference")
} Try / catch
v, err := chain.Extract(c)
if errors.Is(err, extractors.ErrChainCycle) {
return fiber.NewError(fiber.StatusInternalServerError, "extractor misconfigured (cycle)")
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- value not found
- min constraint requires an argument
- max constraint requires an argument
- range constraint requires two arguments
- regex constraint requires a pattern argument
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/65492ed85b27d265.json.
Report an issue: GitHub.