dgraph-io/dgraph · error
not enough JWKUrls
Error message
not enough JWKUrls
What it means
FetchJWK(i) fetches the key set for JWKUrls[i], and guards against the index being out of range. If i is beyond the configured JWKUrls, the slice has fewer entries than expected — an internal invariant violation rather than a network problem. It is raised before any HTTP request is made.
Source
Thrown at graphql/authorization/auth.go:445
// the fetching of key is failed even for one of the JWKUrl.
func (a *AuthMeta) FetchJWKs() error {
if len(a.JWKUrls) == 0 {
return errors.Errorf("No JWKUrl supplied")
}
for i := range a.JWKUrls {
err := a.FetchJWK(i)
if err != nil {
return err
}
}
return nil
}
// FetchJWK fetches the JSON web Key set for the JWKUrl at a given index.
func (a *AuthMeta) FetchJWK(i int) error {
if len(a.JWKUrls) <= i {
return errors.Errorf("not enough JWKUrls")
}
req, err := http.NewRequest("GET", a.JWKUrls[i], nil)
if err != nil {
return err
}
resp, err := a.httpClient.Do(req)
if err != nil {
return err
}
defer func() {
if err := resp.Body.Close(); err != nil {
glog.Warningf("error closing body: %v", err)
}
}()
data, err := io.ReadAll(resp.Body)View on GitHub (pinned to 759e242be6)
Solutions
- Check that JWKUrls is not being mutated (shrunk) concurrently with refreshJWK/FetchJWK — synchronize config reloads.
- Only call FetchJWK with indices obtained by ranging over the current a.JWKUrls.
- Re-fetch/rebuild AuthMeta atomically when JWK configuration changes instead of mutating the slice in place.
- Add a bounds debug log: length of JWKUrls vs requested index to find the offending caller.
- Refresh loop should re-read len(a.JWKUrls) each iteration rather than caching an old count.
Example fix
// before
for i := 0; i < oldCount; i++ { a.FetchJWK(i) }
// after
for i := range a.JWKUrls { a.FetchJWK(i) } Defensive patterns
Strategy: validation
Validate before calling
func safeFetchJWK(a *authorization.AuthMeta, i int) error {
if a == nil || i < 0 || i >= len(a.JWKUrls) {
return fmt.Errorf("index %d out of range for %d JWKUrls", i, len(a.JWKUrls))
}
return a.FetchJWK(i)
} Type guard
func inRange(i, n int) bool { return i >= 0 && i < n } Try / catch
if err := a.FetchJWK(i); err != nil && strings.Contains(err.Error(), "not enough JWKUrls") {
log.Printf("JWK fetch skipped: index %d, len(JWKUrls)=%d", i, len(a.JWKUrls))
return nil // or re-sync config and retry
} Prevention
- Iterate with `for i := range a.JWKUrls` instead of cached lengths
- Guard config reloads with a mutex so JWKUrls is not shrunk mid-refresh
- Rebuild AuthMeta atomically on config change
- Range-check indices before calling FetchJWK directly
When it happens
Trigger: FetchJWK (called by FetchJWKs or refreshJWK) receives i >= len(a.JWKUrls) — e.g. refreshJWK invoked with an index computed against an older, longer JWKUrls list that was later shrunk, or a bad index passed directly.
Common situations: JWKUrls list mutated/reconfigured at runtime (shorter list) while background refresh still iterates old indices; off-by-one or loop bug in custom code calling FetchJWK directly; concurrent config reload racing a refresh.
Related errors
- No JWKUrl supplied
- connection string cannot be empty
- bulk output directory cannot be empty
- failed to open BadgerDB at [%v]: %v
- Cannot load into namespace %#x. It does not exist.
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/c10797332c8d9f19.
Report an issue: GitHub.