gofiber/fiber · critical

state: service not found!

Error message

state: service not found!

What it means

Raised by MustGetService[T Service] (state.go:315) when GetService[T] returns ok==false. Services are stored under a hashed key: servicePrefix (a per-process random hash, servicesStatePrefix + uuid, generated in init at state.go:16) concatenated with hex(srv.String()) via serviceKey (state.go:241-244). A service is only placed into State by App.startServices (services.go:100) AFTER srv.Start() returns nil for entries in fiber.Config.Services. So the panic means one of: the service was never configured, Start() failed so it was never setService'd, the lookup key != srv.String(), or the type parameter T doesn't match the registered concrete type.

Source

Thrown at state.go:315

		}
		return true
	})

	return length
}

// GetService returns a service present in the application's State.
func GetService[T Service](s *State, key string) (T, bool) {
	srv, ok := GetState[T](s, s.serviceKey(key))
	return srv, ok
}

// MustGetService returns a service present in the application's State.
// It panics if the service is not found.
func MustGetService[T Service](s *State, key string) T {
	srv, ok := GetService[T](s, key)
	if !ok {
		panic("state: service not found!")
	}

	return srv
}

View on GitHub (pinned to 9a4c7e57fe)

Solutions

  1. Ensure the service is listed in fiber.Config{Services: []fiber.Service{...}} and that its Start() returns nil — startServices only setService's on success (services.go:98-101).
  2. Make the lookup key byte-identical to srv.String(); use one shared constant at registration and retrieval.
  3. Use fiber.GetService[T] (comma-ok) to handle absence gracefully instead of MustGetService.
  4. Confirm you query the same App whose startServices ran — services live on that app's app.state, keyed by its per-process servicePrefix.

Example fix

// before — panics if service is absent, not started, key mismatches, or wrong type
svc := fiber.MustGetService[*Cache](app.State(), "cache")

// after — derive the key from the service's String() and guard the lookup
const cacheKey = "cache" // == cache.String()
// registration: fiber.Config{Services: []fiber.Service{cache}}
srv, ok := fiber.GetService[*Cache](app.State(), cacheKey)
if !ok {
	return fmt.Errorf("service %q not available (not configured, failed to start, or wrong type)", cacheKey)
}
Defensive patterns

Strategy: validation

Validate before calling

const key = "cache" // must equal cache.String()
srv, ok := fiber.GetService[*Cache](app.State(), key)
if !ok {
	return fmt.Errorf("service %q not available (not configured, Start failed, key mismatch, or wrong type)", key)
}

Type guard

func serviceAvailable[T fiber.Service](s *fiber.State, key string) bool {
	_, ok := fiber.GetService[T](s, key)
	return ok
}

Try / catch

defer func() {
	if r := recover(); r != nil {
		if msg, _ := r.(string); strings.Contains(msg, "service not found") {
			log.Printf("service lookup failed: %v", r)
			return
		}
		panic(r)
	}
}()
svc := fiber.MustGetService[*Cache](app.State(), "cache")

Prevention

When it happens

Trigger: Call fiber.MustGetService[*Cache](app.State(), "cache") when: Cache isn't in app.Config().Services; its Start() returned an error so setService was never called (services.go:98-101); the key passed differs from the service's String() return value; or T differs from the registered concrete type. Also triggered by querying a service on a different App/State instance than the one that ran startServices.

Common situations: Forgetting to add the service to Config.Services; a mismatch between the service's String() implementation and the lookup literal; a service that failed to start silently (error swallowed) or an app boot path that skipped initServices; querying from a second App instance; refactoring String() without updating call sites.

Related errors


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/eee5b09cc1cf4bf7.json. Report an issue: GitHub.