diff --git a/docs/integrations/celery.md b/docs/integrations/celery.md index e45a4dc9..e2378123 100644 --- a/docs/integrations/celery.md +++ b/docs/integrations/celery.md @@ -169,7 +169,7 @@ with container: ## See also - [Testing with overrides](../recipes/testing-overrides.md): swap providers in your tests. -- [Multi-Group organization](../recipes/multi-group.md): structuring a larger container. +- [Organize a large container with multiple Groups](../recipes/multi-group.md): structuring a larger container. - [Lifecycle](../providers/lifecycle.md): finalizers and container teardown. - [Scopes](../providers/scopes.md): the APP → REQUEST lifetime model. diff --git a/docs/integrations/flask.md b/docs/integrations/flask.md index acc8f2be..b8b6ee94 100644 --- a/docs/integrations/flask.md +++ b/docs/integrations/flask.md @@ -197,7 +197,7 @@ assert request_app.test_client().get("/describe").json == [{"method": "GET", "ur ## See also - [Testing with overrides](../recipes/testing-overrides.md): swap providers in your tests. -- [Multi-group organization](../recipes/multi-group.md): structuring a larger container. +- [Organize a large container with multiple Groups](../recipes/multi-group.md): structuring a larger container. - [Lifecycle](../providers/lifecycle.md): finalizers and container teardown. - [Scopes](../providers/scopes.md): the APP → REQUEST lifetime model. diff --git a/docs/integrations/litestar.md b/docs/integrations/litestar.md index 7899aa9e..12595d09 100644 --- a/docs/integrations/litestar.md +++ b/docs/integrations/litestar.md @@ -82,8 +82,9 @@ container.open() Mark every injected parameter with `NamedDependency[...]` from `litestar.di`. Litestar 2.23 deprecated inferring a dependency from a plain annotation, and Litestar 3.0 removes it. -Call `container.validate()` after the plugin is installed. A factory that takes a `litestar.Request` -depends on the context provider that the plugin registers, so validating before it fails with +Call `container.validate()` after `Litestar(...)` is constructed. The plugin registers its context +providers in `on_app_init`, which Litestar runs during construction, and a factory that takes a +`litestar.Request` depends on one of them, so validating before that fails with `ValidationFailedError`. ## Injecting into handlers @@ -223,7 +224,7 @@ with TestClient(request_app) as client: ## See also - [Testing with overrides](../recipes/testing-overrides.md): swap providers in your tests. -- [Multi-group organization](../recipes/multi-group.md): splitting providers across groups, with `autowired_groups`. +- [Organize a large container with multiple Groups](../recipes/multi-group.md): splitting providers across groups, with `autowired_groups`. - [Lifecycle](../providers/lifecycle.md): finalizers and `close_async()`. - [Scopes](../providers/scopes.md): the APP → REQUEST lifetime model. diff --git a/docs/integrations/writing-integrations.md b/docs/integrations/writing-integrations.md index d8bdf1a2..c71985f3 100644 --- a/docs/integrations/writing-integrations.md +++ b/docs/integrations/writing-integrations.md @@ -405,6 +405,8 @@ When you rewrite: - Guard sweeps that apply `@inject` for the user (Flask and aiogram `auto_inject`, Celery `DITask`) against double wrapping with `integrations.is_injected(func)` and `integrations.mark_injected(wrapper)`. +- Say which handlers a sweep leaves alone. aiogram's `auto_inject` skips handlers on `update` + observers, so those need `@inject` by hand, and its page says so. - Leave nested scopes to the caller. Typer's `action_scope(ctx)` yields a fresh `ACTION` child of the per-call container for each `with` block. @@ -445,9 +447,17 @@ Each official integration is its own repository and PyPI package, with the same `ruff` floats forward in CI, so keep `CPY001` in the lint `ignore` list. - In the `modern-di` repo, add `docs/integrations/.md` and a `mkdocs.yml` nav entry under the matching family: Web, Tasks & events, Bots, RPC, CLI or Testing. Model the page on an existing one - such as [Starlette](starlette.md): one compact example with the same two providers as `examples/app.py`, - `container.validate()` after `setup_di`, connection injection in its own "Framework context objects" - section, then framework-specific sections, a `## See also` block, and the `## API` table last. + in the same family, with one compact example using the same two providers as `examples/app.py` and + `container.validate()` after `setup_di`. Web pages such as [Starlette](starlette.md) use + `## Installation`, `## Usage`, `## Injecting into handlers`, `## Scopes and lifecycle`, and + `## Websockets` where the framework has them. Other pages such as [taskiq](taskiq.md) use + `## How to use`, `## Scopes`, `## Root container lifecycle`, and usually `## Testing`. Both kinds + give connection injection its own section, named `## Framework context objects` on every page but + gRPC's and present even when the integration registers no context provider. Framework-specific + sections follow, then a `## See also` block, and the `## API` table last. Write `FromDI` in the + `Annotated` form, except where the framework needs another: the [FastMCP](fastmcp.md) page uses the + default-value form, and the [Litestar](litestar.md) page puts `FromDI` in a route's `dependencies` + mapping. For a provider that must also resolve outside a connection, show an optional parameter (`request: FrameworkType | None = None`), as the [gRPC page](grpc.md#injecting-the-servicercontext) does; [Optional parameters](../providers/context.md#optional-parameters) explains it. diff --git a/docs/introduction/resolving.md b/docs/introduction/resolving.md index 5d53c0a3..98a235b5 100644 --- a/docs/introduction/resolving.md +++ b/docs/introduction/resolving.md @@ -68,7 +68,7 @@ raising. That includes the case where you meant to register the provider and for ## When resolution fails - `resolve(SomeType)` with no provider bound to `SomeType` raises `ProviderNotRegisteredError` - (see [No provider registered for type](../troubleshooting/missing-provider.md)). + (see [ProviderNotRegisteredError](../troubleshooting/missing-provider.md)). - A creator parameter that nothing can satisfy raises `ArgumentResolutionError`, which names the whole dependency chain (see [ArgumentResolutionError](../troubleshooting/argument-resolution-error.md)). diff --git a/docs/migration/to-4.x.md b/docs/migration/to-4.x.md index 3e8b6a8a..ddfc1383 100644 --- a/docs/migration/to-4.x.md +++ b/docs/migration/to-4.x.md @@ -43,7 +43,7 @@ ancestor, emitted `ContainerClosedWarning` and reopened it. In 4.0 the same call `ContainerClosedError` and the container stays closed. `ContainerClosedWarning` is removed, so delete any `filterwarnings` entry that names it. To use a closed container again, reopen it first with `open()` or by re-entering `with` / `async with`, which calls `open()`. See -[Troubleshooting: ContainerClosedError](../troubleshooting/container-closed-error.md). +[ContainerClosedError](../troubleshooting/container-closed-error.md). ### Closing a root container keeps overrides diff --git a/docs/providers/alias.md b/docs/providers/alias.md index 1dc4241f..7500d9c7 100644 --- a/docs/providers/alias.md +++ b/docs/providers/alias.md @@ -111,7 +111,7 @@ inside one `ValidationFailedError`: - `AliasSourceNotRegisteredError` when nothing is registered for `source_type`. - `CircularDependencyError` for a cycle that passes through an alias; see - [Troubleshooting: Circular dependency](../troubleshooting/circular-dependency.md). + [CircularDependencyError](../troubleshooting/circular-dependency.md). - `InvalidScopeDependencyError` when a provider depends, through an alias, on a source at a deeper scope. @@ -142,7 +142,7 @@ cache_container.validate() # .exceptions holds an AliasSourceNotRegisteredError `validate()` applies the [scope dependency rule](scopes.md#the-scope-dependency-rule) through aliases. The error names every hop of the chain and its terminal source, since the alias's own type carries no scope to point at; see - [Troubleshooting: Scope chain](../troubleshooting/scope-chain.md#when-the-dependency-is-reached-through-an-alias). + [InvalidScopeDependencyError: when the dependency is reached through an alias](../troubleshooting/scope-chain.md#when-the-dependency-is-reached-through-an-alias). ## See also diff --git a/docs/providers/context.md b/docs/providers/context.md index 1b276719..412f527d 100644 --- a/docs/providers/context.md +++ b/docs/providers/context.md @@ -292,7 +292,7 @@ kwargs={"request": fastapi_request_provider} # explicit wiring, see Factories: ``` Each integration's page lists its provider names, scopes and types: -[aiohttp](../integrations/aiohttp.md#api), +[aiohttp](../integrations/aiohttp.md#framework-context-objects), [aiogram](../integrations/aiogram.md#framework-context-objects), [FastAPI](../integrations/fastapi.md#framework-context-objects), [FastMCP](../integrations/fastmcp.md#framework-context-objects), diff --git a/docs/providers/lifecycle.md b/docs/providers/lifecycle.md index 9200475e..0c397ab9 100644 --- a/docs/providers/lifecycle.md +++ b/docs/providers/lifecycle.md @@ -178,6 +178,9 @@ A finalizer that raises still drops its cached instance, and the next resolve af builds a fresh one. With `clear_cache=False` the instance is kept, as it is after a finalizer that succeeds. +See [FinalizerError](../troubleshooting/finalizer-error.md) for reading the group and fixing the +finalizers that raised. + ### Async finalizers and `close_sync()` `close_sync()` cannot await. When it reaches an instance with an async finalizer, it adds an @@ -209,8 +212,10 @@ except* exceptions.AsyncFinalizerInSyncCloseError: await container.close_async() # runs the async finalizer ``` -Use `async with container:` or `await container.close_async()` when any provider has an async -finalizer. +Until then the instance stays cached: a repeated `close_sync()` reports it again, and resolving after +a reopen returns the same object. Use `async with container:` or `await container.close_async()` +when any provider has an async finalizer; see +[AsyncFinalizerInSyncCloseError](../troubleshooting/async-finalizer-in-sync-close-error.md). ### Cancelled close @@ -261,7 +266,7 @@ with container: # reopened by __enter__ container.resolve(Settings) ``` -See [Troubleshooting: ContainerClosedError](../troubleshooting/container-closed-error.md) for what to +See [ContainerClosedError](../troubleshooting/container-closed-error.md) for what to check when a container is closed where you did not expect it, and [Migration: To 4.x](../migration/to-4.x.md#resolving-on-a-closed-container-raises) for the 3.x behavior, which warned and reopened instead. @@ -295,7 +300,7 @@ container.validate() # raises ValidationFailedError listing every issue ``` It reports every issue in one `exceptions.ValidationFailedError` instead of stopping at the first; -see [Troubleshooting: ValidationFailedError](../troubleshooting/validation-failed-error.md). An +see [ValidationFailedError](../troubleshooting/validation-failed-error.md). An integration that registers its own providers with `add_providers` should validate after that; see [Writing an integration](../integrations/writing-integrations.md#lifecycle-rules). @@ -306,4 +311,6 @@ adds nothing to resolve time. Call it at startup or in one test. - [Scopes](scopes.md): child containers and which container caches an instance. - [Factories](factories.md): `CacheSettings` is configured on the factory itself. -- [Async resources via lifespan](../recipes/async-lifespan.md): sync creator + async finalizer is the most common shape. +- [Async SQLAlchemy: engine, session, repository](../recipes/sqlalchemy.md): sync creators with async finalizers. +- [Async resources via lifespan](../recipes/async-lifespan.md): resources whose construction needs `await`. +- [FinalizerError](../troubleshooting/finalizer-error.md) and [AsyncFinalizerInSyncCloseError](../troubleshooting/async-finalizer-in-sync-close-error.md): the errors a close can raise. diff --git a/docs/recipes/good-and-bad-practices.md b/docs/recipes/good-and-bad-practices.md index 013d9232..2cf465ac 100644 --- a/docs/recipes/good-and-bad-practices.md +++ b/docs/recipes/good-and-bad-practices.md @@ -33,7 +33,7 @@ class Dependencies(Group): `container.validate()` reports the broken version before anything resolves: it raises `ValidationFailedError` carrying an `InvalidScopeDependencyError`; see -[Scope chain violation](../troubleshooting/scope-chain.md). Without `validate()`, the first resolve of +[InvalidScopeDependencyError](../troubleshooting/scope-chain.md). Without `validate()`, the first resolve of `UserCache` raises `ScopeNotInitializedError`, whose message names both `UserCache` and `Session`, on the first request that reaches it instead of at startup. diff --git a/docs/recipes/multi-group.md b/docs/recipes/multi-group.md index 47f465bc..7edf3d97 100644 --- a/docs/recipes/multi-group.md +++ b/docs/recipes/multi-group.md @@ -109,6 +109,7 @@ await container.close_async() - Two providers for the same type make `Container(groups=[...])` raise `DuplicateProviderTypeError`, whichever groups they are in. Give one of them `bound_type=None` and pass it to its consumers through [`kwargs`](../providers/factories.md#kwargs); see [DuplicateProviderTypeError](../troubleshooting/duplicate-type-error.md). - A provider object belongs to one group. Assigning it to a second group (`engine = Database.engine`) registers it twice and raises the same `DuplicateProviderTypeError`. To use another group's provider, depend on its type, or reference it in `kwargs={"engine": Database.engine}`. +- Passing one group twice, or a group together with its subclass, also registers the same providers twice and raises `DuplicateProviderTypeError`, with a `bound_type=None` hint that does not apply. Pass each group once; for a subclass, pass only the subclass. See [issue #669](https://github.com/modern-python/modern-di/issues/669). - `Container` ignores attribute names, so two groups can both have a `session` attribute. Litestar's `autowired_groups` and `modern-di-pytest`'s `expose()` do use them: the first warns and keeps the provider from the last group, and the second raises `ValueError`. - The order of `groups=[...]` does not matter. Nothing checks the combined graph for you, so call `container.validate()` at startup. diff --git a/docs/recipes/testing-overrides.md b/docs/recipes/testing-overrides.md index 0ead9ca0..b59d40b3 100644 --- a/docs/recipes/testing-overrides.md +++ b/docs/recipes/testing-overrides.md @@ -223,6 +223,7 @@ Under the default mode, a `session.rollback()` in the code under test rolls back - Overrides are global to the container tree. Override on any container and every container sharing its root sees the replacement. That is what tests want; keep it in mind if you ever override outside tests. - `override` is keyed by provider object. Pass `Dependencies.user_repository`, not the string `"user_repository"`, which raises `AttributeError`. - Always reset. A leaked override reaches every later test that shares the container, and nothing reports it. With a session-scoped container, set overrides in a function-scoped fixture with `with container.override(...)`, so they are reset after each test even when it fails. +- Watch cached dependents. A cached instance (`cache=True`) keeps the dependencies it was built with, so overriding one of its dependencies does not reach an instance already in the cache, and an instance first built under an override keeps the fake after the override ends. Override the cached provider itself, or build the tests that need the fake a fresh container. [Pytest integration: Overrides](../integrations/pytest.md#overrides) has the same caveat for session-scoped fixtures. - Override the right level. If you override the engine but tests resolve the session, the session's creator still runs, so the replacement has to be something that creator accepts. If a test relies on a specific session, override the session itself. ## See also diff --git a/docs/troubleshooting/context-not-set.md b/docs/troubleshooting/context-not-set.md index 8859e0cf..a831004a 100644 --- a/docs/troubleshooting/context-not-set.md +++ b/docs/troubleshooting/context-not-set.md @@ -20,43 +20,11 @@ When a creator body calls `container.resolve(TenantId)` itself, the chain ends a ### 1. The value is set on a container of a different scope -A `ContextProvider` reads only the container of its own scope, and context never propagates between -containers; see [context propagation](../providers/context.md#context-propagation). A value set on -any other container is invisible to it, in either direction: - -- A `ContextProvider(TenantId, scope=Scope.REQUEST)` does not see a value set on the APP parent. -- A `ContextProvider(TenantId, scope=Scope.APP)` does not see a value set on a REQUEST child. - - - -```python -# Broken: the TenantId provider is REQUEST-scoped, so the APP value is never read. -app_container.set_context(TenantId, TenantId("acme")) -request_container = app_container.build_child_container(scope=Scope.REQUEST) -``` - -Set the value on the container whose scope matches the provider's scope, either when building it or -afterwards: - -```python -# Works: -request_container = app_container.build_child_container( - scope=Scope.REQUEST, - context={TenantId: TenantId("acme")}, -) - -# Works: -request_container = app_container.build_child_container(scope=Scope.REQUEST) -request_container.set_context(TenantId, TenantId("acme")) -``` +A `ContextProvider` reads only the container of its own scope, so a value set on a parent or a child +container never reaches it. Set the value on the container whose scope matches the provider's +scope, with `context=` when building it or `set_context()` afterwards; +[Context propagation](../providers/context.md#context-propagation) shows both, and the rule in each +direction. If the value really is per request, declare the provider with `scope=Scope.REQUEST`. If it is one value for the whole app, declare it with `scope=Scope.APP` and set it on the APP container. @@ -76,6 +44,13 @@ value still raises. See [Optional parameters](../providers/context.md#optional-p To make the value optional for every consumer, direct resolves included, give the provider a default. See [Optional context: `default=`](../providers/context.md#optional-context-default): + + ```python tenant = providers.ContextProvider(TenantId, scope=Scope.REQUEST, default=None) ``` @@ -86,3 +61,4 @@ tenant = providers.ContextProvider(TenantId, scope=Scope.REQUEST, default=None) - [When no value is set](../providers/context.md#when-no-value-is-set): what each kind of consumer gets. - [Scopes](../providers/scopes.md): per-container context and why it never propagates. - [Async resources via lifespan](../recipes/async-lifespan.md): the "construct in lifespan, inject as context" pattern. +- [Migration: a missing context value for a required parameter raises `ContextValueNotSetError`](../migration/to-4.x.md#a-missing-context-value-for-a-required-parameter-raises-contextvaluenotseterror): the 3.x behavior, and why `except ArgumentResolutionError` no longer catches it. diff --git a/docs/troubleshooting/creator-call-error.md b/docs/troubleshooting/creator-call-error.md index 53d6af65..6ba09e5b 100644 --- a/docs/troubleshooting/creator-call-error.md +++ b/docs/troubleshooting/creator-call-error.md @@ -31,6 +31,8 @@ rejected when the `Factory` is declared, as An exception raised inside the creator's body, a `TypeError` included, propagates as itself and is never wrapped in this error. +A `ResolutionError` raised by a `container.resolve()` call in the body keeps its class too, and gains +the creator's step in its `.dependency_path`, so its message draws the chain down to that creator. ## Fix diff --git a/docs/troubleshooting/duplicate-type-error.md b/docs/troubleshooting/duplicate-type-error.md index f8c124d1..3e29c011 100644 --- a/docs/troubleshooting/duplicate-type-error.md +++ b/docs/troubleshooting/duplicate-type-error.md @@ -28,6 +28,13 @@ same `bound_type` when: - two factories' creators return the same type, such as a primary and a replica `DatabaseConfig`; - two groups passed to the same container each declare a provider for the type. +The same provider object registered twice raises it too, with both bullets naming one provider and +`.first_provider is .second_provider`. That happens when a group and its subclass are both passed, +when one group is passed twice, or when one provider is assigned in two groups. The hint about +`bound_type=None` does not apply here. Pass each group once, and for a subclass pass only the +subclass, which already holds the base group's providers. This is tracked in +[issue #669](https://github.com/modern-python/modern-di/issues/669). + ## Fix If the two providers stand for different things, give each its own type. A thin subclass is enough, diff --git a/docs/troubleshooting/finalizer-error.md b/docs/troubleshooting/finalizer-error.md index 2ad25fee..7c652e0c 100644 --- a/docs/troubleshooting/finalizer-error.md +++ b/docs/troubleshooting/finalizer-error.md @@ -80,8 +80,10 @@ What `except*` does not catch is raised again as a `FinalizerError` holding only errors. A finalizer that raised is not retried. Its instance is dropped from the cache, so a later close does -not call that finalizer again, and resolving after a reopen builds a new instance. Because every other -finalizer still ran, a broken one does not leak a resource that a later finalizer would have closed. +not call that finalizer again, and resolving after a reopen builds a new instance. With +`clear_cache=False` the instance stays cached and a reopen returns it, but its finalizer still does +not run again. Because every other finalizer still ran, a broken one does not leak a resource that a +later finalizer would have closed. An `AsyncFinalizerInSyncCloseError` entry is the exception to this: `close_sync()` keeps that instance cached, and a later `await container.close_async()` runs its finalizer. See diff --git a/docs/troubleshooting/unsupported-creator-parameter-error.md b/docs/troubleshooting/unsupported-creator-parameter-error.md index 634a2d3e..3850edc1 100644 --- a/docs/troubleshooting/unsupported-creator-parameter-error.md +++ b/docs/troubleshooting/unsupported-creator-parameter-error.md @@ -55,6 +55,7 @@ providers.Factory(create_thing, scope=Scope.APP) ``` ```python +# Works: def create_thing(items: tuple[Item, ...] = ()) -> Thing: return Thing(items) diff --git a/mkdocs.yml b/mkdocs.yml index 86f9d7ef..c28781a9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -45,7 +45,7 @@ nav: - Recipes: - Async SQLAlchemy: recipes/sqlalchemy.md - Async resources via lifespan: recipes/async-lifespan.md - - Multi-Group organization: recipes/multi-group.md + - Multi-group organization: recipes/multi-group.md - Testing with overrides: recipes/testing-overrides.md - Request-scoped engine selection: recipes/request-scoped-engine.md - Good and bad practices: recipes/good-and-bad-practices.md @@ -58,20 +58,20 @@ nav: - Invalid scope type: troubleshooting/invalid-scope-type-error.md - Container closed: troubleshooting/container-closed-error.md - Validation failed: troubleshooting/validation-failed-error.md - - Missing provider for type: troubleshooting/missing-provider.md + - Provider not registered: troubleshooting/missing-provider.md - Alias source not registered: troubleshooting/alias-source-not-registered-error.md - Alias bound to its source: troubleshooting/alias-bound-to-source-error.md - Argument resolution error: troubleshooting/argument-resolution-error.md - Circular dependency: troubleshooting/circular-dependency.md - Creator call error: troubleshooting/creator-call-error.md - ContextProvider has no value: troubleshooting/context-not-set.md - - Duplicate type error: troubleshooting/duplicate-type-error.md + - Duplicate provider type: troubleshooting/duplicate-type-error.md - Child container registration: troubleshooting/child-container-registration-error.md - Group scope conflict: troubleshooting/group-scope-conflict-error.md - Provider scope frozen: troubleshooting/provider-scope-frozen-error.md - Unknown factory kwarg: troubleshooting/unknown-factory-kwarg-error.md - Unsupported creator parameter: troubleshooting/unsupported-creator-parameter-error.md - - Scope chain violation: troubleshooting/scope-chain.md + - Invalid scope dependency: troubleshooting/scope-chain.md - Scope enum mismatch: troubleshooting/scope-enum-mismatch-error.md - Finalizer error: troubleshooting/finalizer-error.md - Async finalizer in sync close: troubleshooting/async-finalizer-in-sync-close-error.md @@ -178,7 +178,7 @@ plugins: - providers/lifecycle.md: How instances are created, cached, and cleaned up - providers/factories.md: Regular vs cached Factory providers - providers/context.md: Injecting runtime context values with ContextProvider - - providers/container.md: The auto-registered provider that resolves to the Container itself + - providers/container.md: "The Container API: building containers, a map of its methods, injecting the container itself, and registering or looking up providers" - providers/alias.md: Binding one type to an already-registered provider - providers/errors-and-exceptions.md: The ModernDIError exception hierarchy - providers/advanced-api.md: Low-level extension points for library authors @@ -205,19 +205,20 @@ plugins: - troubleshooting/invalid-scope-type-error.md: Diagnosing InvalidScopeTypeError - troubleshooting/container-closed-error.md: Diagnosing ContainerClosedError - troubleshooting/validation-failed-error.md: Diagnosing ValidationFailedError - - troubleshooting/missing-provider.md: Diagnosing missing provider registration errors + - troubleshooting/missing-provider.md: Diagnosing ProviderNotRegisteredError - troubleshooting/alias-source-not-registered-error.md: Diagnosing AliasSourceNotRegisteredError + - troubleshooting/alias-bound-to-source-error.md: Diagnosing AliasBoundToSourceError - troubleshooting/argument-resolution-error.md: Diagnosing ArgumentResolutionError - - troubleshooting/circular-dependency.md: Diagnosing circular dependency errors + - troubleshooting/circular-dependency.md: Diagnosing CircularDependencyError - troubleshooting/creator-call-error.md: Diagnosing CreatorCallError - - troubleshooting/context-not-set.md: Diagnosing ContextProvider-has-no-value errors - - troubleshooting/duplicate-type-error.md: Diagnosing duplicate bound_type registration errors + - troubleshooting/context-not-set.md: Diagnosing ContextValueNotSetError + - troubleshooting/duplicate-type-error.md: Diagnosing DuplicateProviderTypeError - troubleshooting/child-container-registration-error.md: Diagnosing ChildContainerRegistrationError - troubleshooting/group-scope-conflict-error.md: Diagnosing GroupScopeConflictError - troubleshooting/provider-scope-frozen-error.md: Diagnosing ProviderScopeFrozenError - troubleshooting/unknown-factory-kwarg-error.md: Diagnosing UnknownFactoryKwargError - troubleshooting/unsupported-creator-parameter-error.md: Diagnosing UnsupportedCreatorParameterError - - troubleshooting/scope-chain.md: Diagnosing scope chain violation errors + - troubleshooting/scope-chain.md: Diagnosing InvalidScopeDependencyError - troubleshooting/scope-enum-mismatch-error.md: Diagnosing ScopeEnumMismatchError - troubleshooting/finalizer-error.md: Diagnosing FinalizerError - troubleshooting/async-finalizer-in-sync-close-error.md: Diagnosing AsyncFinalizerInSyncCloseError