---
title: "custodian_unqualified"
url: https://services.dev/docs/reference/check/custodian_unqualified
---
# custodian_unqualified

URL: https://services.dev/docs/reference/check/custodian_unqualified

> A subject's custodian ladder leaves the brand of record for a role whose credential the brand doesn't hold.

| Fix | Fails in | Suggests | Exit |
|---|---|---|---|
| Put a role that holds the credential ahead of 'brand' in custodian, or declare the brand's credential in brand.ts. | `services/translation.ts:9` · `subject.of_record.custodian` | `subject.of_record.custodian: ['translator', 'brand']` | 1 |

**Owned by** [Of record](https://services.dev/docs/people/of-record.md): the page that explains what this gate holds.

## What check says

```txt title="npx services.dev check"
  ✗ A subject's custodian ladder leaves the brand of record for a role whose credential the brand doesn't hold. Put a role that holds the credential ahead of 'brand' in custodian, or declare the brand's credential in brand.ts. translation's certified translation names the brand as custodian of record for the translator, and the brand holds no sworn translator: put a role that does first.
    at services/translation.ts:9 · subject.of_record.custodian
✗ 1 to fix
```

## The failing file

```ts title="services/translation.ts"
import { Service } from 'services.dev'
import rules from '../rules.ts'

export default Service({
  name: 'Translation',
  input: { document: 'file', to: 'language: a BCP 47 tag, such as fr-CA' },
  output: { document: 'file' },
  rules,
  subject: { kind: 'certified translation', key: 'document', of_record: { role: 'translator', named_at: 'sign', custodian: ['brand'] } },
  roles: { translator: { credential: 'sworn translator' }, reviewer: { credential: 'sworn translator' } },
  deliver: {
    translate: 'ai',
    harden: { review: 'adversarial', lenses: ['meaning', 'terms'] },
    sign: { by: 'translator', stamp: true },
  },
  price: 89,
})
```

## The fix

```diff title="git add -A && git diff --staged"
diff --git a/services/translation.ts b/services/translation.ts
index 59ba02a..e0b0ae5 100644
--- a/services/translation.ts
+++ b/services/translation.ts
@@ -6,7 +6,7 @@ export default Service({
   input: { document: 'file', to: 'language: a BCP 47 tag, such as fr-CA' },
   output: { document: 'file' },
   rules,
-  subject: { kind: 'certified translation', key: 'document', of_record: { role: 'translator', named_at: 'sign', custodian: ['brand'] } },
+  subject: { kind: 'certified translation', key: 'document', of_record: { role: 'translator', named_at: 'sign', custodian: ['reviewer', 'brand'] } },
   roles: { translator: { credential: 'sworn translator' }, reviewer: { credential: 'sworn translator' } },
   deliver: {
     translate: 'ai',
```

```txt title="npx services.dev check"
✓ ready to sell · 1 Service · it keeps at least 80% of every job
```

## The rest of the brand

```ts title="rules.ts"
import { Rules } from 'services.dev'

export default Rules({
  version: '2026-10',
  services: {
    translation: {
      sign: { reserved: 'sworn translator', where: '*', position: 'A sworn translator signs a translation filed with a registry.' },
    },
  },
})
```

## In the legal example

How the legal example passes this gate, in lines read from its files.

```ts title="examples/legal/pools/attorneys.ts"
roles: {
// …
  practitioner: { credential: ['patent attorney', 'patent agent'], where: '*' },
```

```ts title="examples/legal/services/provisional-patent.ts"
subject: {
```

Read them in context: [The attorneys' Pool](https://services.dev/docs/examples/legal/pool.md), [Provisional patent application](https://services.dev/docs/examples/legal/provisional-patent.md).

## Explained in

- [Of record](https://services.dev/docs/people/of-record.md)

## What an agent reads

```json title="npx services.dev check --json · the custodian_unqualified failure"
{
  "code": "custodian_unqualified",
  "reason": "A subject's custodian ladder leaves the brand of record for a role whose credential the brand doesn't hold.",
  "next": "Put a role that holds the credential ahead of 'brand' in custodian, or declare the brand's credential in brand.ts. translation's certified translation names the brand as custodian of record for the translator, and the brand holds no sworn translator: put a role that does first.",
  "doc_url": "https://services.dev/docs/reference/check/custodian_unqualified",
  "file": "services/translation.ts",
  "line": 9,
  "path": "subject.of_record.custodian",
  "suggest": {
    "path": "subject.of_record.custodian",
    "value": "['translator', 'brand']"
  }
}
```

<details>
<summary>The whole document check --json prints</summary>

```json title="npx services.dev check --json"
{
  "ai": {
    "cents_per_call": 42,
    "simulated": true
  },
  "mcp": {
    "tools": 13,
    "tokens": 4490,
    "sandbox": 9,
    "budget": 8000
  },
  "files": [
    {
      "path": "rules.ts",
      "lines": 6,
      "kind": "rules",
      "says": "rules 2026-10 · 1 Service · 1 row"
    }
  ],
  "services": [
    {
      "path": "services/translation.ts",
      "lines": 12,
      "steps": "translate · ai → harden · ai · adversarial · 2 lenses → sign · translator · * · stamped",
      "ok": false,
      "price": "$89 per job, within 48 hours, charged on delivery.",
      "who": "A translator signs every document before delivery. (rules 2026-10)",
      "roles": [
        "translator · sworn translator · your staff",
        "reviewer · sworn translator · your staff"
      ],
      "rules": "2026-10",
      "subject": "certified translation · keyed by document · the translator who does sign stays of record · then brand",
      "boundary": {
        "full": [
          "reserved sign to sworn translator"
        ]
      },
      "agent": {
        "tool": "order_translation",
        "words": 26,
        "job": "job_7Hq2",
        "status": "waiting",
        "on": "person",
        "charged": null,
        "person": true,
        "why": ""
      },
      "ledger": "+$89.00 · AI $1.26 (example) · you $87.74",
      "approved_ledger": null,
      "outcome": null,
      "margin": {
        "floor": {
          "cents": 7120,
          "pct": 80
        },
        "own": 7120,
        "stop": 1780,
        "nested": []
      },
      "apps": [
        "customer portal",
        "delivery portal",
        "owner console"
      ],
      "failures": [
        {
          "code": "custodian_unqualified",
          "reason": "A subject's custodian ladder leaves the brand of record for a role whose credential the brand doesn't hold.",
          "next": "Put a role that holds the credential ahead of 'brand' in custodian, or declare the brand's credential in brand.ts. translation's certified translation names the brand as custodian of record for the translator, and the brand holds no sworn translator: put a role that does first.",
          "doc_url": "https://services.dev/docs/reference/check/custodian_unqualified",
          "file": "services/translation.ts",
          "line": 9,
          "path": "subject.of_record.custodian",
          "suggest": {
            "path": "subject.of_record.custodian",
            "value": "['translator', 'brand']"
          }
        }
      ]
    }
  ]
}
```

</details>

---

- Up: [check’s gates](https://services.dev/docs/reference/check.md)
- Previous: [sheet_without_consent](https://services.dev/docs/reference/check/sheet_without_consent.md)
- Next: [pool_role_unknown](https://services.dev/docs/reference/check/pool_role_unknown.md)
