goxdi uses sentinel errors. Branch with errors.Is — do not compare error strings.
import "errors"
_, err := goxdi.Get[*Repo](scope)
if errors.Is(err, goxdi.ErrNotRegistered) {
// …
}| Sentinel | Typical cause |
|---|---|
ErrNotRegistered |
Resolving a type that was never Add*-ed |
ErrAlreadyRegistered |
Second Add* for the same T on one builder |
ErrScopeRequired |
Resolving a scoped type from the root container |
ErrClosed |
Get / Close after the scope or root was closed |
ErrScopeClosed |
Alias of ErrClosed (kept for compatibility) |
ErrCircularDependency |
Factory cycle detected during creation |
Surfaces at resolve time, including when a factory asks for a missing dependency.
_ = goxdi.AddSingleton(b, func(r goxdi.Resolver) (*Repo, error) {
db, err := goxdi.Get[*DB](r) // not registered
if err != nil {
return nil, err
}
return &Repo{DB: db}, nil
})
_, err := goxdi.Get[*Repo](root)
// errors.Is(err, goxdi.ErrNotRegistered)Prefer failing boot by resolving the app entrypoint once before serving.
Avoid treating “not registered” as a normal control-flow signal in hot paths unless optional deps are a deliberate design.
Returned by Add* when T already exists. The original registration is unchanged.
err := goxdi.AddSingleton(b, secondFactory)
if errors.Is(err, goxdi.ErrAlreadyRegistered) {
// keep first factory; do not assume override
}Means “this type needs a unit-of-work boundary”.
_, err := goxdi.Get[*UnitOfWork](root)
if errors.Is(err, goxdi.ErrScopeRequired) {
scope := root.NewScope()
defer scope.Close()
uow, err := goxdi.Get[*UnitOfWork](scope)
_ = uow
_ = err
}Returned when using a closed scope/root, including a second Close. Prefer ErrClosed; ErrScopeClosed is the same sentinel.
Prefer:
scope := root.NewScope()
defer scope.Close()
// resolve only while scope is openAvoid storing a scope on a long-lived struct and resolving after the request finished.
The error wraps the sentinel and includes a type path. Break the cycle in your model; see Resolving.
If a factory returns a custom error, Get returns it as-is (it is not rewritten into a sentinel).
_ = goxdi.AddSingleton(b, func(goxdi.Resolver) (*DB, error) {
return nil, fmt.Errorf("open db: %w", errOpen)
})You may wrap sentinels yourself if you need more context:
db, err := goxdi.Get[*DB](r)
if err != nil {
return nil, fmt.Errorf("repo: %w", err)
}MustGet panics with the same error value Get would return. That panic is recoverable with recover, but recovering DI failures usually hides misconfiguration — prefer Get at recoverable boundaries.
- API reference — error variable declarations
- Resolving — where errors arise in the graph
- Registering services — duplicate registration behavior