ADR-0024: ResourceLocked Error Type¶
Status¶
| Field | Value |
|---|---|
| Status | Accepted |
| Supersedes | — |
| Superseded by | — |
| Amends | — |
Revised 2026-06-03 in place rather than superseded — by
the time the rewrite landed the ADR was unimplemented against, so
there was no caller state to preserve and a superseding ADR would
have added a level of indirection without aiding any reader. The
rewrite is material (it dropped the speculative lock_owner
attribute reservation and triggered the spec 005 ERR-013
co-amendment); a future audit reading this file should note that the
supersession discipline was traded for in-place clarity, scoped to
the four Graph ADRs (0021..0024).
Context¶
Microsoft Graph returns HTTP 423 Locked with an error code of
resourceLocked when an item is held by another session — typical
causes are an open co-authoring session in the Office clients, a
checked-out document in SharePoint, or an in-progress upload session
on the same item. The condition is:
- Not a permissions problem. The caller is authenticated and authorised; the resource itself is temporarily unavailable.
- Not a throttling problem. There is no
Retry-Afterpromise, and the condition may last seconds, minutes, or indefinitely. - Not "resource missing". The item exists.
- Retryable with caution. A short bounded retry may succeed, but blind exponential retry could wait forever.
None of the existing remote_store errors capture this accurately:
PermissionDenied— wrong: the caller has permission.AlreadyExists— wrong: the file is not a write conflict.BackendUnavailable— wrong: the backend is reachable and responsive.RemoteStoreError(generic) — loses the actionable signal.
No other backend in the project today emits 423 or an equivalent
condition, so the error type does not exist yet. With Graph, it does.
Decision¶
Add ResourceLocked as a new concrete error type. The decisions:
- A new type, not a reuse. None of the existing errors fit HTTP
423: the caller is authorised (notPermissionDenied), it is not a write conflict (notAlreadyExists), the backend is reachable (notBackendUnavailable), and genericRemoteStoreErrorloses the actionable "locked now, may clear" signal. - Flat under
RemoteStoreError. One level deep, no intermediate category (ERR-008). path+backendonly; nolock_owner. Graph does not surface the lock holder and no other backend emits this today, so a speculative field is dropped (no-speculative-API rule). Reverse (widen the class) only when a backend genuinely surfaces the holder, via a covering spec amendment — ERR-013 points back here for exactly this reasoning.- Terminal; caller-driven retry. Not retried by the default policy (RET-015); callers choose their own cadence.
- Reusable across backends. Future equivalents — SharePoint
check-out, SMB lock conflicts, WebDAV
423— map to the same type; that reuse is why this is a canonical error, not a Graph-local one. Graph's423 resourceLockedis the only mapped source today (GR-045 owns the mapping).
Consequences¶
- Honest error signal. Graph callers distinguish "locked right now" from "permission denied" or "service unavailable" and react appropriately (e.g. surface a user-visible "this file is open in Word, close it and retry" message).
- Hierarchy growth, one member. ERR-008's flat shape is
preserved.
remote_store.__all__gainsResourceLocked. - Retry-policy interaction. The default retry policy does not
treat
ResourceLockedas transient. Documented in spec 025 (RET-015). - Future-proofing without speculation. The error exists for any future backend that genuinely needs it; the class stays minimal until a real second consumer arrives.
- Ships as a coupled bundle. The runtime class, the spec 005
ERR-013 entry, the Dafny
Error.ResourceLocked(path, backend)variant, and its_raise_if_errtest dispatch land together, never the variant alone. Delivered under ID-127 (GR-CONTRACT step) — seesdd/BACKLOG.md; the detailed coupling mechanics live in spec 005,sdd/formal/BackendContract.dfy, and BACKLOG ID-127. - No supersession. This ADR does not supersede or deprecate any prior ADR.
References¶
sdd/specs/005-error-model.md(ERR-008 flat hierarchy, ERR-013)sdd/specs/025-retry-policy.md(RET-015)sdd/specs/044-graph-backend.md(GR-045)- RFC-0010: Microsoft Graph Backend (error mapping section)