In a VCF environment, lifecycle operations are expected to be performed through SDDC Manager/VCF Operations. However, in real-world scenarios, operational mistakes occur—especially when components are modified directly in vCenter Server rather than through the VCF control plane.
In this blog, I will walk through a failure scenario involving NSX Advanced Load Balancer (Avi) in a VCF 9 environment, where Avi controller VMs were accidentally deleted from vCenter, leaving behind stale inventory references in SDDC Manager. I will cover the issue, impact, recovery approach, and key lessons.
The Problem Scenario
In a VCF-9 environment, Avi was deployed via SDDC Manager (integrated with NSX) and was running fine. During a troubleshooting session, Avi controller nodes were deleted directly from vCenter, leaving stale entries in the SDDC Manager UI and thus preventing the redeployment of Avi.
Result: SDDC Manager still believed Avi was deployed, and NSX integration references remained. The deletion option was grayed out in the SDDC manager UI.
This created a split-brain condition between the actual infrastructure state (Avi missing) and the VCF inventory state (Avi still present).
Root Cause
VCF maintains strict lifecycle state tracking via SDDC Manager. When components are altered outside their control:
- Inventory drift occurs.
- Internal metadata (database + APIs) becomes inconsistent.
- Dependent services (NSX, VCF Automation) retain stale references.
In this case, deleting Avi directly from vCenter bypassed SDDC Manager’s lifecycle workflows.
Resolution: Clean Up Stale Entries in SDDC Manager
Removing a stale Avi instance from the SDDC Manager inventory may involve the following:
- API calls
- Database edits.
- Guided VMware KB procedures (custom scripts)
The end goal is to ensure the SDDC Manager no longer believes Avi is deployed.
1: API Calls: The API call to remove Avi from SDDC Manager was failing as the API was invoking a workflow, and the workflow failed because it couldn’t reach Avi controllers.
However, the API to remove Avi references from NSX Manager was successful. The following API calls were executed:
|
1 2 3 |
DELETE https://{{nsx_mgr}}/policy/api/v1/alb/controller-nodes/clusterconfig DELETE https://{{nsx_mgr}}/policy/api/v1/infra/sites/default/enforcement-points/alb-endpoint |
2: Database Edit: Since the SDDC manager API call failed, the next step was to investigate stale entries in the database and remove them.
Disclaimer: Don’t attempt the following steps in a prod environment and without Broadcom support, as modifying the database can be catastrophic and can lead to inconsistent states and outages.
2.1 Connect to the SDDC Manager database
|
1 |
/usr/pgsql/15/bin/psql --host=localhost -U postgres -d platform |
2.2: Search Avi controller entries
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
platform=# select id,cluster_name,cluster_fqdn,deployment_status from nsx_alb_controller_cluster; id | cluster_name | cluster_fqdn | deployment_status --------------------------------------+--------------+---------------------------+------------------- 4ab98fbd-f94b-45db-9068-1cff9bb84096 | vcf9-avicl01 | vcf9-avi.cmb1.thinkon.lab | ACTIVE (1 row) platform=# select * from nsx_alb_cluster_and_domain_and_nsx_cluster; id | nsx_alb_controller_cluster_id | domain_id | nsx_id ----+--------------------------------------+--------------------------------------+-------------------------------------- 55 | 4ab98fbd-f94b-45db-9068-1cff9bb84096 | df223713-1190-421f-8a31-286ac4c24919 | 68671e4b-dd30-4272-bca1-2bff9040a8f0 (1 row) platform=# select id,credentialtype,entityid from credential where entitytype = 'NSX_ALB'; id | credentialtype | entityid --------------------------------------+----------------+-------------------------------------- db1d3e67-7bfd-4701-8512-c3f5fca453ac | API | 4ab98fbd-f94b-45db-9068-1cff9bb84096 (1 row) platform=# \c operationsmanager You are now connected to database "operationsmanager" as user "postgres". operationsmanager=# SELECT id,resource_id,resource_fqdn,fetch_status FROM certificatemanagement.certificate_expiry where resource_fqdn = 'vcf9-avi.cmb1.thinkon.lab'; id | resource_id | resource_fqdn | fetch_status ----+--------------------------------------+---------------------------+-------------- 15 | 4ab98fbd-f94b-45db-9068-1cff9bb84096 | vcf9-avi.cmb1.thinkon.lab | FAILED (1 row) |
2.3: Clean Avi controller entries
The commands below remove the Avi instance details as well as Avi ‘admin’ credentials and certificates.
|
1 2 3 4 5 6 7 8 9 10 11 |
platform=# delete from nsx_alb_controller_cluster where id = '4ab98fbd-f94b-45db-9068-1cff9bb84096'; DELETE 1 platform=# delete from nsx_alb_cluster_and_domain_and_nsx_cluster where nsx_alb_controller_cluster_id = '4ab98fbd-f94b-45db-9068-1cff9bb84096'; DELETE 1 platform=# delete from credential where id = 'db1d3e67-7bfd-4701-8512-c3f5fca453ac'; DELETE 1 operationsmanager=# delete FROM certificatemanagement.certificate_expiry where resource_id = '4ab98fbd-f94b-45db-9068-1cff9bb84096'; DELETE 1 |
After that, I refreshed the SDDC Manager UI, and “Deploy Avi Load Balancer” was available. And that’s when I thought the job was done. But there was more to it than meets the eye.
The redeploy attempt failed at step “Create NSX Service users for Avi Load Balancer”
The error was pretty evident in the domainmanager.log
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
2026-04-16T12:28:53.088+0000 ERROR [vcf_dm,69e0d602b04ffda511da86a0c7b7a6fd,f630] [c.v.v.c.n.s.c.c.ComplexHelpers,dm-exec-17] Exception occurred during NSX API invocation java.util.concurrent.ExecutionException: com.vmware.vapi.std.errors.ConcurrentChange: ConcurrentChange (com.vmware.vapi.std.errors.concurrent_change) (statusCode:409) => { messages = [], data = => {error_message=User 'svc-vcf9-avi-vcf9-nsx' already exists., error_code=36149, module_name=node-services}, errorType = CONCURRENT_CHANGE } at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396) at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2073) at com.vmware.vapi.bindings.CompletionStageFuture.get(CompletionStageFuture.java:52) at com.vmware.vcf.common.nsxt.sdk.client.connection.ComplexHelpers.invoke(ComplexHelpers.java:169) at com.vmware.vcf.common.nsxt.sdk.client.connection.NodeUserOperations.createServiceUser(NodeUserOperations.java:46) at com.vmware.vcf.common.nsxt.sdk.client.connection.NsxtManagerNodeUserOperations.createServiceUser(NsxtManagerNodeUserOperations.java:92) at com.vmware.vcf.nsxalbmanager.fsm.actions.CreateNSXServiceUsersAction.createUserInNsx(CreateNSXServiceUsersAction.java:283) at com.vmware.vcf.nsxalbmanager.fsm.actions.CreateNSXServiceUsersAction.createNsxServiceAccount(CreateNSXServiceUsersAction.java:220) at com.vmware.vcf.nsxalbmanager.fsm.actions.CreateNSXServiceUsersAction.execute(CreateNSXServiceUsersAction.java:191) at com.vmware.vcf.nsxalbmanager.fsm.actions.CreateNSXServiceUsersAction.execute(CreateNSXServiceUsersAction.java:50) at com.vmware.evo.sddc.orchestrator.platform.action.FsmActionState.invoke(FsmActionState.java:66) at com.vmware.evo.sddc.orchestrator.platform.action.FsmActionPlugin.invoke(FsmActionPlugin.java:161) at com.vmware.evo.sddc.orchestrator.platform.action.FsmActionPlugin.invoke(FsmActionPlugin.java:147) at com.vmware.evo.sddc.orchestrator.core.ProcessingTaskSubscriber.invokeMethod(ProcessingTaskSubscriber.java:403) at com.vmware.evo.sddc.orchestrator.core.ProcessingTaskSubscriber.processTask(ProcessingTaskSubscriber.java:517) at com.vmware.evo.sddc.orchestrator.core.ProcessingTaskSubscriber.accept(ProcessingTaskSubscriber.java:128) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at com.google.common.eventbus.Subscriber.invokeSubscriberMethod(Subscriber.java:85) at com.google.common.eventbus.Subscriber.lambda$dispatchEvent$0(Subscriber.java:71) at com.vmware.vcf.common.tracing.TraceRunnable.run(TraceRunnable.java:63) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:840) Caused by: com.vmware.vapi.std.errors.ConcurrentChange: ConcurrentChange (com.vmware.vapi.std.errors.concurrent_change) (statusCode:409) => { messages = [], data = => {error_message=User 'svc-vcf9-avi-vcf9-nsx' already exists., error_code=36149, module_name=node-services}, errorType = CONCURRENT_CHANGE } 2026-04-16T12:28:53.097+0000 ERROR [vcf_dm,69e0d602b04ffda511da86a0c7b7a6fd,f630] [c.v.v.n.f.a.CreateNSXServiceUsersAction,dm-exec-17] Error during NSX user svc-vcf9-avi-vcf9-nsx creation. Error: ConcurrentChange (com.vmware.vapi.std.errors.concurrent_change) (statusCode:409) => { messages = [], data = => {error_message=User 'svc-vcf9-avi-vcf9-nsx' already exists., error_code=36149, module_name=node-services}, errorType = CONCURRENT_CHANGE } 2026-04-16T12:28:53.098+0000 ERROR [vcf_dm,69e0d602b04ffda511da86a0c7b7a6fd,f630] [c.v.v.n.f.a.CreateNSXServiceUsersAction,dm-exec-17] Avi ALB Cluster service user creation failed - {"nsxAlbClusterId":"d583b0e7-a994-420a-82f7-69fe2da11c95","nsxClusterId":"68671e4b-dd30-4272-bca1-2bff9040a8f0","nsxRemoteEndpoint":{"address":"vcf9-nsx.cmb1.thinkon.lab","port":0,"username":"svc-vcf9-sddcm01-vcf9-nsx-4831","password":"*****"},"nsxForDeployment":"68671e4b-dd30-4272-bca1-2bff9040a8f0"} |
Once again, I had to modify the database to remove the service account entry.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
platform=# select id,username,credentialtype from credential where entitytype='NSXT_MANAGER'; id | username | credentialtype --------------------------------------+----------------------------------+---------------- 00d1c0c1-c41a-4e4b-91fe-e58063a6e72f | admin | API d5d62e02-c9c8-4569-b86b-092a76a67ba9 | root | SSH eebc566d-6148-4d87-b22a-17d05b11d6c0 | audit | AUDIT 7420bf3f-a8a6-4ebe-ac54-0fca42a4d144 | svc-vcf9-sddcm01-vcf9-nsx-4831 | API c78202d8-1759-4e2f-8e70-df186f6d374d | svc-vcf9-avi-vcf9-nsx | API (5 rows) platform=# select id,credential_id from credentialhistory; id | credential_id --------------------------------------+-------------------------------------- f4a84ebd-c51e-40ba-8f37-02d63af85d30 | 92b7026d-a6f5-47d6-abc7-bd0d824b3daa 7cefbb9e-dbaa-49dc-bc5a-e749d51aa66a | 7420bf3f-a8a6-4ebe-ac54-0fca42a4d144 f30da8ed-153f-4f4b-bb2e-7267fb69641a | 8b200571-f36d-48da-84d4-b1f3e130bd59 c835490a-d7f9-423e-8371-0e7c248fee5f | c78202d8-1759-4e2f-8e70-df186f6d374d (4 rows) platform=# delete from credentialhistory where credential_id='c78202d8-1759-4e2f-8e70-df186f6d374d'; DELETE 1 platform=# delete from credential where id='c78202d8-1759-4e2f-8e70-df186f6d374d'; DELETE 1 |
Reattempted the deployment, and again it failed with the same error. On further investigation, I found that the problem is not on the SDDC manager side, but on the NSX side. The SDDC manager was trying to create the service account ‘svc-vcf9-avi-vcf9-nsx’, but it already exists on the NSX manager.
First, I listed the local user via API, but it failed, complaining that the user doesn’t exist.
Next, I listed the role-bindings and found the service account instance.
But when I tried deleting the role-binding, it errored out.
The error “Role binding for local user can not be deleted” (error code 71004) is a deliberate NSX restriction. Here’s what’s happening and how to work around it:
Why does the DELETE fail?
NSX does not allow you to delete a role binding directly for local users via the /api/v1/aaa/role-bindings/{id} endpoint. Local user accounts in NSX have restrictions — you cannot simply add or delete role bindings for them through the standard role-binding API. The role binding for a local user is managed through the user account itself, not through the role-bindings endpoint.
The /api/v1/aaa/role-bindings DELETE endpoint is intended for external/LDAP/VIDM users, not local users. For local users, manage roles via the user account APIs or the UI.
Since the user was not available in the GUI/API output, I decided to clean the entries from the NSX corfu database.
Interacting with NSX Corfu Database
NSX 9.0 uses /opt/vmware/bin/corfu_tool_runner.py — a Python wrapper — instead of the old Java JAR commands to interact with the corfu database.
List the RoleBinding table
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/opt/vmware/bin/corfu_tool_runner.py -n nsx -o showTable --tool corfu-browser -t RoleBinding <-------snipped output-------> {"Key": { "stringId": "de22d9f5-7241-439a-9885-074fc068e244" }} ,{"Payload": { "managedResource": { "displayName": "svc-vcf9-avi-vcf9-nsx" }, "name": "svc-vcf9-avi-vcf9-nsx", "type": "local_user", "role": ["enterprise_admin"], "identityType": "ROLE_BINDING_IDENTITY_TYPE_ENUM_VIDM_PI_LOCAL_ROLE_BINDING", "etcPasswdId": "11003", "rolesForPath": [{ "path": "/", "role": ["enterprise_admin"] }], "lowercaseName": "svc-vcf9-avi-vcf9-nsx" }} ,{"Metadata": { "revision": "1", "createTime": "1770833016726", "createUser": "node-mgmt", "lastModifiedTime": "1770833016933", "lastModifiedUser": "svc-vcf9-sddcm01-vcf9-nsx-4831", "productVersion": "9.0.2.0" } |
Delete Avi Service Account
|
1 2 3 4 5 6 7 8 9 10 11 |
/opt/vmware/bin/corfu_tool_runner.py -n nsx -o deleteRecord --tool corfu-editor -t RoleBinding --keyToDelete='{"stringId": "de22d9f5-7241-439a-9885-074fc068e244"}' ====================== Deleting 1 records in table RoleBinding and namespace nsx. Stream Id ee042c24-df64-3908-b349-ea7ba6f1e869 Namespace: nsx TableName: RoleBinding 2026-04-17T05:04:37.971Z | INFO | main | o.c.runtime.view.SMRObject | ObjectBuilder: open Corfu stream nsx$RoleBinding id ee042c24-df64-3908-b349-ea7ba6f1e869 2026-04-17T05:04:37.972Z | INFO | main | o.c.runtime.view.SMRObject | Added SMRObject [ee042c24-df64-3908-b349-ea7ba6f1e869, PersistentCorfuTable] to objectCache 0: Deleting record with Key {"stringId": "de22d9f5-7241-439a-9885-074fc068e244"} 1 records deleted successfully. |
3: Delete the underlying local user account
|
1 2 3 4 |
root@vcf9-nsx03:~# getent passwd 11003 svc-vcf9-avi-vcf9-nsx:x:11003:1002:,,,:/home/svc-vcf9-avi-vcf9-nsx:/usr/sbin/nologin curl -k -u 'admin:<passwd>' -X DELETE 'https://localhost/api/v1/node/users/11003' |
4: Verify the role binding is gone
After cleaning up NSX, I restarted the Avi deployment task, and it completed without any further issues.
Conclusion
In a production environment, it’s not recommended to modify product databases directly. The best is to open a Broadcom support case. Broadcom might have custom scripts/commands to deal with stale entries cleanup.
That’s it for this post. I hope you enjoyed reading it. Feel free to share it on social media if it’s worth sharing.





