{"record":{"id":"60271c68e5101062","repo":"apolloconfig/apollo","slug":"check-lock-for-s-failed-please-retry","errorCode":null,"errorMessage":"Check lock for %s failed, please retry.","messagePattern":"Check lock for (.+?) failed, please retry\\.","errorType":"exception","errorClass":"ServiceException","httpStatus":500,"severity":"error","filePath":"apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/aop/NamespaceAcquireLockAspect.java","lineNumber":158,"sourceCode":"        throw e;\n      }\n    } else {\n      // check lock owner is current user\n      checkLock(namespace, namespaceLock, currentUser);\n    }\n  }\n\n  private void tryLock(long namespaceId, String user) {\n    NamespaceLock lock = new NamespaceLock();\n    lock.setNamespaceId(namespaceId);\n    lock.setDataChangeCreatedBy(user);\n    lock.setDataChangeLastModifiedBy(user);\n    namespaceLockService.tryLock(lock);\n  }\n\n  private void checkLock(Namespace namespace, NamespaceLock namespaceLock, String currentUser) {\n    if (namespaceLock == null) {\n      throw new ServiceException(\n          String.format(\"Check lock for %s failed, please retry.\", namespace.getNamespaceName()));\n    }\n\n    String lockOwner = namespaceLock.getDataChangeCreatedBy();\n    if (!lockOwner.equals(currentUser)) {\n      throw new BadRequestException(\n          \"namespace:\" + namespace.getNamespaceName() + \" is modified by \" + lockOwner);\n    }\n  }\n\n\n}\n","sourceCodeStart":140,"sourceCodeEnd":171,"githubUrl":"https://github.com/apolloconfig/apollo/blob/d95fc18d112589efc09ddcbe1507047584d55251/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/aop/NamespaceAcquireLockAspect.java#L140-L171","documentation":"A ServiceException (HTTP 500) thrown from NamespaceAcquireLockAspect.checkLock() when a namespace lock row is null after a failed concurrent insert. This occurs during the optimistic-locking namespace lock flow: two callers race to insert a NamespaceLock row; the loser catches DataIntegrityViolationException, re-queries the lock, and if it is STILL null (the winner's transaction was rolled back or the row was deleted), this error fires. It is inherently transient — the message itself says 'please retry.'","triggerScenarios":"Two concurrent mutations (create/update/delete item, or change-set update) on the same namespace when namespace.lock.switch is enabled (bizConfig.isNamespaceLockSwitchOff() returns false). The first thread wins the INSERT; the second gets a unique-constraint violation, re-queries, and finds no row because the winner rolled back.","commonSituations":"High-concurrency edits to the same Apollo namespace from multiple portals or API clients; a previous edit transaction rolled back due to another validation failure, leaving no committed lock row; testing with parallel requests against a single namespace.","solutions":["Retry the request after a short delay — the error message explicitly advises this and the condition is transient.","Enable namespace.lock.switch (apollo biz config) consistently across all admin service instances so that the locking flow is deterministic.","If the error is persistent rather than transient, check for orphaned/rolled-back NamespaceLock rows in the database and verify transaction integrity.","Reduce concurrent callers editing the same namespace by serializing writes at the application level."],"exampleFix":"// before: fire-and-forget with no retry\nopenApi.createItem(appId, env, cluster, namespace, itemDTO);\n\n// after: retry with backoff for transient ServiceException\nint maxRetries = 3;\nfor (int i = 0; i <= maxRetries; i++) {\n    try {\n        openApi.createItem(appId, env, cluster, namespace, itemDTO);\n        break;\n    } catch (ServiceException e) {\n        if (e.getMessage().contains(\"please retry\") && i < maxRetries) {\n            Thread.sleep(200L * (i + 1));\n            continue;\n        }\n        throw e;\n    }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Retry with exponential backoff for transient lock race\nint maxRetries = 3;\nfor (int attempt = 0; attempt <= maxRetries; attempt++) {\n    try {\n        openApi.createItem(appId, env, cluster, namespace, itemDTO);\n        break;\n    } catch (ServiceException e) {\n        if (e.getMessage().contains(\"please retry\") && attempt < maxRetries) {\n            Thread.sleep(200L * (attempt + 1));\n            continue;\n        }\n        throw e;\n    }\n}","preventionTips":["Enable namespace.lock.switch consistently across all admin service instances for deterministic locking.","Serialize concurrent writes to the same namespace from the same integration to avoid lock contention.","Monitor for persistent lock-check failures which indicate transaction-rollback issues."],"tags":["concurrency","locking","namespace-lock","retryable","service-exception","apollo-adminservice"],"backgroundTag":null,"analyzedSha":"d95fc18d112589efc09ddcbe1507047584d55251","analyzedAt":"2026-08-14T04:00:05.477Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}