---
outline: deep
---

# DF0037: Duplicate Service Provider

## Message

> A service is already provided under "`{id}`".

## Cause

`ctx.services` holds exactly one provider per service id. A second `provide()` under the same id throws instead of silently replacing a service another integration may already hold a reference to.

## Example

```ts
// ✗ Bad — provided twice
ctx.services.provide('my-plugin:sources', hostA)
ctx.services.provide('my-plugin:sources', hostB)

// ✓ Good — revoke the previous provider first
const revoke = ctx.services.provide('my-plugin:sources', hostA)
revoke()
ctx.services.provide('my-plugin:sources', hostB)
```

## Fix

- Revoke the existing provider first — `provide()` returns a revoke function.
- If the collision is between two unrelated integrations, namespace the id with your plugin id (`<plugin-id>:<service>`), the same rule RPC function names follow.
- Guard idempotent setup paths with `ctx.services.has(id)`.

## Source

- [`packages/devframe/src/node/host-services.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/host-services.ts) — `provide()` throws this when the id is already taken.
