For AI agents: markdown of this page — /docs-content-en/infra/deploy/lock.md documentation index — /llms.txt

Release a stuck lock

DELETE /v1/infra/servers/:id/lock

Forcibly releases a stuck operation lock on the server. Use it when /exec or /deploy was aborted from the client side (lost connection, local timeout), but the lock is still active on the server and subsequent calls return EXEC_BUSY. This is the LAST recovery step, not the first: the lock is released UNCONDITIONALLY, so it comes after retries at the Retry-After interval and the guarded /unstick, and only once the server is independently confirmed idle — by its state and its logs. The endpoint always returns 200: if a lock was held on this replica — it is released, the response carries released: true and localLock: true; if not — released: false (also a success).

The recovery sequence below is performed by the holder of the key that manages the server. Development-team keys can call lock release but cannot read the operation list/status or call /unstick; ask the managing-key holder to perform those steps. Team callers must also obtain independent proof that the server is idle before releasing a lock. A route permission alone never proves idleness.

The call has two different scopes, and they must not be conflated. ON THIS replica the release is unconditional — which is why the independent idleness check belongs precisely here. The broadcast to all replicas (broadcast: true) is narrower, and deliberately so: a peer releases the lock only if it holds it itself and only if it is an exec one; a live foreign deploy is left alone. So the endpoint does clear a stuck exec lock held on another replica — which is exactly why released can be false while the lock really was held and released on the holder replica. released/localLock describe only the current replica and are not proof of a fleet-wide release — do not poll the endpoint in a loop until released: true. Instead, read the previous operation outcome before deciding whether to retry (/exec//deploy). An EXEC_BUSY that survives this call does NOT by itself prove the agent is holding it: the broadcast deliberately leaves a foreign live deploy lock alone, so it may equally be a deploy on another replica. error.hint tells them apart: with autoExpiresInSeconds it is the platform lock and the thing to wait out; without it, a synchronous command or, on STANDALONE, a durable job may occupy the agent channel. First read the server operations with kind=exec and their outcomes. The absence of that field does not prove a leaked mutex. The guarded /unstick is appropriate only for a confirmed leaked synchronous mutex on an independently confirmed idle dedicated virtual machine (kind: "STANDALONE"). On a galaxy host and a Galaxy application the call returns 409 GALAXY_UNSTICK_UNSUPPORTED, because the exec channel is shared; there the remaining options are to retry at the Retry-After interval and, if the refusal persists, to contact support. The broadcast is best-effort (a no-op when only one replica is active, or if the bus is down); a guaranteed release of a stuck exec lock comes from the server-side TTL auto-sweep (below).

Use with care. Releasing the lock of an active operation can lead to an unpredictable server state — /exec and /deploy running at the same time may compete for files and systemd units.

On STANDALONE, a running durable job keeps the execution channel busy after 202 releases the platform lock. Poll its operation; an unknown outcome needs support and independently confirmed full termination. Missing autoExpiresInSeconds does not prove a leaked mutex. Recovering the tunnel or releasing the lock does not remove the restriction on starting another durable job. Galaxy commands run synchronously with a 600-second limit and share the host channel across all applications and deploys; your own operation list may not show another application’s job, so an empty list does not prove the host is idle.

Parameters

Parameter In Type Required Description
Parameterid Inpath Typestring (UUID) Requiredyes DescriptionServer ID. List: GET /v1/infra/servers. The ID of a deleted server managed by this key appears in the list with includeDeleted=true

The request body is empty.

Examples

curl — personal key

Terminal
curl -X DELETE -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/lock

curl — OAuth application

Terminal
curl -X DELETE -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/lock

JavaScript — personal key

javascript
const res = await fetch(
  `https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/lock`,
  {
    method: 'DELETE',
    headers: { 'X-Api-Key': 'YOUR_API_KEY' },
  }
)
const { data } = await res.json()

if (data.released) {
  console.log(`Released lock ${data.operation}, held for ${data.ageMs}ms, ${data.expiresInMs}ms left before expiry`)
} else {
  // No local lock, but the release was broadcast to other replicas (data.broadcast === true).
  console.log(data.message)
}

JavaScript — OAuth application

javascript
await fetch(
  `https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/lock`,
  {
    method: 'DELETE',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
    },
  }
)

Response fields

Field Type Description
Fieldsuccess Typeboolean DescriptionAlways true when called on an existing server
Fielddata.released Typeboolean Descriptiontrue — a lock was held on this replica and it was released. false — no local lock. Describes only the current replica, not the whole fleet
Fielddata.localLock Typeboolean DescriptionWhether the lock was held on this very replica (true when released: true)
Fielddata.broadcast Typeboolean Descriptiontrue — the release was broadcast to the other replicas. Delivery is requested but not confirmed, and the broadcast does nothing when only one replica is active or the bus is down
Fielddata.operation Typestring DescriptionType of the released operation: "exec" or "deploy". Present only when released: true
Fielddata.ageMs Typenumber DescriptionHow many milliseconds the lock had been active. Present only when released: true
Fielddata.expiresInMs Typenumber DescriptionIn how many milliseconds the lock would have expired on its own. Present only when released: true
Fielddata.message Typestring DescriptionA note that there was no local lock and the release was broadcast to the replicas. Present only when released: false

Response example

A lock was held on this replica — released:

JSON
{
  "success": true,
  "data": {
    "released": true,
    "localLock": true,
    "broadcast": true,
    "operation": "deploy",
    "ageMs": 320000,
    "expiresInMs": 580000
  }
}

No local lock (the release was broadcast to other replicas):

JSON
{
  "success": true,
  "data": {
    "released": false,
    "localLock": false,
    "broadcast": true,
    "message": "No lock on this replica; a fleet-wide EXEC-lock release was broadcast to peers"
  }
}

Error response example

404 — server not found:

JSON
{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Server not found"
  }
}

Errors

HTTP Code Description
HTTP401 CodeMISSING_API_KEY DescriptionNo API key was supplied through X-Api-Key or a supported Authorization: Bearer scheme
HTTP401 CodeINVALID_API_KEY DescriptionThe authentication key is not recognized
HTTP401 CodeKEY_INACTIVE DescriptionThe requesting API key is no longer active
HTTP401 CodeKEY_EXPIRED DescriptionThe requesting API key has expired
HTTP401 CodeNO_PORTAL DescriptionA non-management key has no portal binding
HTTP401 CodeCOWORK_CHAT_KEY_INACTIVE DescriptionThe parent device key behind a Cowork chat key is no longer usable
HTTP401 CodeWRONG_AUTH_SCHEME DescriptionAn OAuth application key was sent as a Bearer session: put the key in X-Api-Key and the session in Authorization: Bearer
HTTP401 CodeINVALID_SESSION DescriptionThe supplied OAuth session is invalid or expired
HTTP401 CodeTOKEN_EXPIRED DescriptionThe OAuth user token expired and its refresh failed; re-authorization is required
HTTP401 CodeTOKEN_INVALID DescriptionWhen the partner AI plane is enabled, its supplied token is unknown or expired
HTTP401 CodeKEY_REVOKED DescriptionThe partner credential behind the AI plane token is revoked
HTTP402 CodeACCOUNT_FROZEN DescriptionThe key owner’s account is frozen. With wallet-debt scoping disabled, the shared API-key guard refuses this call before its handler. Follow error.topupUrl to resolve the balance; this status alone does not authorize repeating a prior write.
HTTP403 CodeINFRA_FORBIDDEN_FOR_COWORK_KEY DescriptionThe call was made with a Cowork key — such a key works with data only and cannot perform write operations. To issue a key that can, see Project key for deploy
HTTP403 CodePORTAL_COLLABORATOR_KEY_WRONG_SERVER DescriptionThe development-team key is bound to another server
HTTP403 CodePORTAL_COLLABORATOR_NOT_A_MEMBER DescriptionDevelopment-team membership ended or the current role no longer permits this operation
HTTP403 CodeWRITE_BLOCKED_READONLY_KEY DescriptionA read-only key cannot make this write; for lock release this applies to MANAGEMENT keys despite the exemption for APP and chat keys.
HTTP403 CodeEXTERNAL_COLLABORATOR_KEY_OUT_OF_SCOPE DescriptionThis operation is outside the external-collaborator key route list. Use the key that manages the server
HTTP403 CodeIP_NOT_ALLOWED DescriptionThe caller IP is outside the key allowlist.
HTTP403 CodeOWNER_BLOCKED DescriptionThe key owner is blocked.
HTTP403 CodeOWNER_DELETED DescriptionThe key owner was deleted.
HTTP403 CodePORTAL_SUSPENDED DescriptionThe bound portal is suspended.
HTTP403 CodePORTAL_DELETED DescriptionThe bound portal was deleted.
HTTP403 CodePORTAL_BLOCKED DescriptionThe bound portal is blocked.
HTTP403 CodeMANAGEMENT_KEY_NO_ENTITY_ACCESS DescriptionThe management key lacks the portal binding or entity authority required by this call.
HTTP403 CodeAGENT_MAINTENANCE_KEY_OUT_OF_SCOPE DescriptionThe maintenance key route list does not include this operation.
HTTP403 CodeAPP_API_KEY_OUT_OF_SCOPE DescriptionThe application key route list does not include this operation.
HTTP403 CodeWAITLIST_PENDING DescriptionThe key owner has not been activated.
HTTP403 CodeSESSION_APP_MISMATCH DescriptionThe OAuth session belongs to another application.
HTTP403 CodePLANE_FORBIDDEN DescriptionThe partner key does not allow this AI plane.
HTTP403 CodeSYSTEM_FORBIDDEN DescriptionThe partner key does not allow this AI system.
HTTP403 CodeSCOPE_FORBIDDEN DescriptionThe partner AI plane forbids this route.
HTTP403 CodeCONNECT_COMPANY_ROUTE_FORBIDDEN DescriptionA company connection key does not allow this route.
HTTP404 CodeNOT_FOUND DescriptionThe server does not exist or belongs to another API key. An exception is a development-team key with a current ADMIN or DEVELOPER role on this server.
HTTP409 CodeAGENT_WRITE_ALREADY_EXECUTED DescriptionWith the agent-write replay guard enabled, this exact DELETE by the runtime agent key already has a claim and was not repeated. error.firstExecutedAt is the first claim timestamp; error.firstStatus is its HTTP status or null while the first attempt is still in flight. Reconcile and report that result; do not automatically repeat an unknown outcome. Failed first attempts release their claims
HTTP429 CodeQUOTA_EXCEEDED DescriptionAPI billing is enabled with a nonzero overage price: the daily free quota is exhausted and the PREPAY balance is not positive. Top up the balance. error.quota and error.used report counts; X-RateLimit-Quota, X-RateLimit-Used and X-RateLimit-Remaining report the quota, usage and zero remainder. This refusal does not promise Retry-After or X-RateLimit-Scope
HTTP429 CodeCALLER_RATE_LIMITED DescriptionThe shared key or user request limit. Wait the seconds in Retry-After; X-RateLimit-Scope identifies the refusing layer
HTTP429 CodeRATE_LIMITED DescriptionLock-release limit: 6 requests per minute per key–server pair. The limit is divided across backend replicas; x-ratelimit-limit reports the effective ceiling and Retry-After reports the waiting time
HTTP503 CodeACCOUNT_PENDING_ERASURE DescriptionThe key owner is pending erasure or being erased. Header Retry-After: 3600.
HTTP503 CodeSERVICE_DISABLED DescriptionThe partner AI plane or its quota-readiness service is disabled. No Retry-After is promised for this refusal.

Full list of common API errors — Errors.

Known specifics

  • One lock per server. Protection against races between /exec and /deploy — they share one common lock. It is impossible to lock an individual command.
  • Auto-release on normal completion. /exec and /deploy release the lock themselves, whether they succeed or fail. DELETE /lock is only needed when the client aborted the connection before completion or the agent timed out without sending a final event.
  • Platform lock TTL — auto-expiry without a call. Synchronous /exec sets the lock for timeout + 30 + 60 seconds. /deploy — for 15 minutes. Even without DELETE /lock, a stuck lock will expire on its own.
  • The release is broadcast to all replicas. The platform scales horizontally, and a stuck lock is held on the replica that took it, which is not necessarily the one serving your DELETE /lock. So the release is always broadcast fleet-wide (broadcast: true) — that is how the endpoint releases the lock on the holder replica. That is also why released can be false even when the lock really was released: the local replica did not hold it.
  • Guaranteed auto-release of a stuck exec lock. Even without DELETE /lock, a stuck exec lock is guaranteed to be released by a server-side background sweep shortly after its TTL expires (on the order of a few minutes) — for the case where the handler could not release it itself. DELETE /lock is the fast path; the sweep is the safety net. (There is no sweep for /deploy: a long deploy may legitimately exceed its TTL; a stuck deploy lock is released by DELETE /lock or by the operation finishing.)
  • released: false is a success, not an error. The endpoint does not return 404 when there is no lock, because the idea is to "guarantee there is no lock". The client does not care whether there was one or not.
  • Works in any server mode. Unlike most Deploy API endpoints, DELETE /lock does not require BLACKHOLE — the lock is held in the platform's memory and does not depend on the agent.
  • The lock outlives server deletion. A stuck lock survives its server: if the previous server was deleted but its in-memory lock remained, the next deploy fails with EXEC_BUSY. DELETE /lock releases such a lock if the deleted server record and its binding to the managing API key are retained. Only the managing key can use this recovery path. A development-team key receives 403 PORTAL_COLLABORATOR_NOT_A_MEMBER after server deletion, even if the key is still active and its membership record remains.

See also