In VMware Cloud Foundation Automation (VCFA) 9.1 environments, custom resource actions exhibit the following behavior:
Cloud.vSphere.Machine disappear from the UI action listREST API omits the custom action from the JSON response array while standard built-in actions remain present. Design > Resource Actions and re-saving the action temporarily restores visibility in the UI, but the action vanishes again later anywhere from about 30 minutes up to a few hours, depending on timing.ProviderRegistrationService component, which is invoked by the ProviderRegistrationScheduler task running inside the catalog-service-app pod.ProviderRegistrationScheduler task checks whether a provider's declared catalog has changed since the last run. When a change is detected, the ProviderRegistrationService rewrites the provider's resource types and actions.The script periodically re-saves all custom Day-2 actions via the API.
Copy resave-script.zip attached to this KB to an appropriate location on the system where the script will be executed (a jump server, or the VCFA host itself).
Extract the archive.
Linux/Photon OS:
python3 -m zipfile -e resave-script.zip .Windows:
python -m zipfile -e resave-script.zip .Go to the vcfa-resave directory.
Download the VCFA certificate. The certificate should be saved in vcfa-resave directory.
Linux/Photon OS:
openssl s_client -connect <VCFA_HOST>:443 -showcerts </dev/null 2>/dev/null | sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' > vcfa-cert.pemWindows:
ⓘ The click path above (padlock → "Connection is secure" → "Certificate is valid") matches Chrome at the time of writing. Other browsers, or a future browser update, may use slightly different wording or icons for the same flow. In general: after clicking the padlock/site-information icon, look for a certificate or "connection is secure" option in the popup — this leads to the certificate viewer, after which the Certification Path → root certificate → Copy to File steps above still apply the same way.
Get an API token for the VCFA user.
VCFA_REFRESH_TOKEN=<the token you copied>chmod 600 credentialsGet the VCFA org name and org id.
Perform a dry run to verify the script can authenticate to VCFA and correctly identify all the custom Day-2 actions it would resave, without making any actual changes.
Linux/Photon OS:
python3 resave_custom_actions.py https://<VCFA_HOST> <org_name> <org_id> --creds-file ./credentials --cacert ./vcfa-cert.pem --dry-runWindows:
python resave_custom_actions.py https://<VCFA_HOST> <org_name> <org_id> --creds-file .\credentials --cacert .\vcfa-cert.cer --dry-run
Messages are logged to resave_actions.log in the same directory. A successful dry run looks like:
2026-08-13T12:37:31+05:30 [DRY RUN] Would resave 'Deployment.custom.customaction1'.
2026-08-13T12:37:32+05:30 [DRY RUN] Would resave 'Cloud.vSphere.Machine.custom.customaction2'.
2026-08-13T12:37:32+05:30 [DRY RUN] Resave complete: 2 succeeded, 0 missing, 0 failed.A successful actual run (without --dry-run) looks like:
2026-08-13T12:37:52+05:30 Resaved 'Deployment.custom.customaction1' successfully.
2026-08-13T12:37:54+05:30 Resaved 'Cloud.vSphere.Machine.custom.customaction2' successfully.
2026-08-13T12:37:54+05:30 Resave complete: 2 succeeded, 0 missing, 0 failed.Schedule the script to run every 20 minutes.
Linux/Photon OS (systemd):
Create /etc/systemd/system/vcfa-resave-custom-actions.service:
[Unit]
Description=Resave VCFA custom resource actions
[Service]
Type=oneshot
User=<name of the logged in user>
ExecStart=/usr/bin/python3 <absolute path resave_custom_actions.py> https://<host> <org-name> <org-id> --creds-file <absolute path credentials file> --cacert <absolute path vcfa-cert.pem>Create /etc/systemd/system/vcfa-resave-custom-actions.timer:
[Unit]
Description=Run resave_custom_actions.py
[Timer]
OnBootSec=5min
OnUnitActiveSec=20min
[Install]
WantedBy=timers.targetThen, run the following commands to enable the service:
sudo systemctl daemon-reload
sudo systemctl enable --now vcfa-resave-custom-actions.timerWindows (Task Scheduler):
Create a batch wrapper run-vcfa.bat in the same directory:
@echo off
cd /d "<\path\to>\vcfa-resave"
<\path\to>\python.exe resave_custom_actions.py https://<host> <org-name> <org-id> --creds-file credentials --cacert vcfa-cert.cerOpen Task Scheduler → Create Task...
By default, the background job that can trigger this bug runs every 30 minutes. This step slows it down to once every 24 hours, so a custom action you've resaved is far less likely to disappear again before the next scheduled resave.
Impact: This also slows down how quickly any change to a provider's registered resource types or actions takes effect. For example, if a feature toggle changes which resource types or actions a provider exposes, that change will now take up to 24 hours to appear in (or disappear from) the catalog, instead of up to 30 minutes.
Log in to a VCFA node as vmware-system-user.
Switch to root and export configuration:
sudo -i
export KUBECONFIG=/etc/kubernetes/admin.confCheck whether JAVA_TOOL_OPTIONS is already set on the catalog-service-app deployment in the prelude namespace:
kubectl get deployment catalog-service-app -n prelude -o jsonpath='{.spec.template.spec.containers[*].env[?(@.name=="JAVA_TOOL_OPTIONS")].value}'If the above command returns content, include it alongside the two new flags so existing settings aren't overwritten:
kubectl set env deployment/catalog-service-app -n prelude JAVA_TOOL_OPTIONS="<existing value from step 3> -Dprovider.register.fixedDelayMillis=86400000 -Dprovider.register.initialDelayMillis=86400000"If it returns nothing, run:
kubectl set env deployment/catalog-service-app -n prelude JAVA_TOOL_OPTIONS="-Dprovider.register.fixedDelayMillis=86400000 -Dprovider.register.initialDelayMillis=86400000"⚠ Note: applying this automatically restarts the pod(s).
Verify it took effect:
kubectl get pods -n prelude -l app=catalog-service-app # confirm pods recreated (new AGE)
kubectl exec -n prelude <new-pod-name> -- env | grep JAVA_TOOL_OPTIONSⓘ Even with this workaround in place, a custom action can still disappear for a brief period — this cannot be eliminated entirely until the permanent fix (9.1.1.0200) is installed. This can happen in two circumstances: a restart of the catalog-service-app pod (for example, during planned maintenance), or the scheduler's own periodic tick, which — now that Step 2 has slowed it to once every 24 hours — still has one guaranteed opportunity per day to fire due to the underlying ordering defect. Pod restarts are irregular and environment-specific.
In either case, the action will be missing for no longer than your configured resave-script interval — the script's next scheduled run will find and restore it automatically, with no action required from you. If you need it back sooner, you can restore it immediately at any time by either running resave_custom_actions.py manually (without --dry-run), or by re-saving the action from Design > Resource Actions in the UI.