VCF 9.1.1 • Offline Depot • Troubleshooting

VCF 9.1.1 Offline Depot: When a Known-Good Depot Fails in the UI but Works Through the API

Refreshing a reusable VCF offline depot with 9.1.1 metadata was straightforward. Connecting a brand-new VCF 9.1.1 Installer to that same proven depot was not. This is the exact troubleshooting path that isolated the URL validation problem and the API workaround that fixed it.

Published September 2026 • Lab walkthrough • VCF Installer 9.1.1

I already had a working HTTPS offline depot for VCF 9.1.0. The goal was simple: add the signed 9.1.1 metadata, deploy a fresh 9.1.1 VCF Installer, point it at the existing depot, and reuse the binaries and metadata from one central location. The depot itself was healthy. The surprise was that the VCF 9.1.1 UI rejected the URL before it even tried to use it.

TL;DRThe offline depot was fine. The VCF 9.1.1 URL-style configuration rejected https://vcf-depot.home.local as invalid. The same Installer accepted the depot immediately when it was configured through the API with separate hostname and port fields, after which a metadata sync exposed both VCF 9.1.0.0 and 9.1.1.0 in Binary Management.

Lab environment

Offline depotvcf-depot.home.local
ProtocolHTTPS / TCP 443 / Basic Auth
Apache document root/var/www/vcf-depot
VCF content root/var/www/vcf-depot/PROD
Existing installerVCF Installer 9.1.0
New installervcf-i911.home.local / VCF 9.1.1
VCF 9.1.1 appliance build25713928
Metadata packagemetadata-20260908-101000.zip

1. Get the signed VCF 9.1.1 offline metadata

The key artifact was not another copy of the Download Tool. It was the signed offline-depot metadata package published with VCF 9.1.1 in the Broadcom Support Portal:

Broadcom Support Portal showing metadata-20260908-101000.zip labeled VCF offline depot metadata
Broadcom Support Portal: the 9.1.1 release includes metadata-20260908-101000.zip, identified as VCF offline depot metadata.

I first inspected and extracted the archive into a scratch directory rather than overwriting the live depot:

unzip -l metadata-20260908-101000.zip | \
  egrep 'productVersionCatalog|vcfManifest|Compatibility|vsan|metadata'

rm -rf /tmp/vcf-911-metadata
mkdir -p /tmp/vcf-911-metadata
unzip metadata-20260908-101000.zip -d /tmp/vcf-911-metadata

The package contained exactly the pieces I wanted to see:

PROD/metadata/productVersionCatalog/v1/productVersionCatalog.json PROD/metadata/productVersionCatalog/v1/productVersionCatalog.sig PROD/metadata/manifest/v1/vcfManifest.json PROD/metadata/Compatibility/... PROD/metadata/vsan/hcl/... PROD/COMP/VCENTER/.../upgrade_info.xml

Then I validated the catalog and confirmed that the signed PVC contained 9.1.1 entries:

PVC=/tmp/vcf-911-metadata/PROD/metadata/productVersionCatalog/v1/productVersionCatalog.json

jq empty "$PVC" && echo "PVC JSON is valid"

jq -r '
  .patches
  | to_entries[]
  | .value[]?
  | .productVersion // empty
' "$PVC" |
grep '^9\.1\.1' |
sort -Vu
Important:The Product Version Catalog is signed. Do not hand-edit productVersionCatalog.json. Keep the JSON and productVersionCatalog.sig together as the signed pair provided by Broadcom.

2. Merge the new metadata without destroying the working depot

Because the existing depot already contained VCF 9.1.0 binaries, I backed up the current metadata and merged the new package into the live PROD tree. The critical detail here is not using --delete.

sudo mkdir -p /var/backups/vcf-depot

sudo tar -C /var/www/vcf-depot \
  -czf /var/backups/vcf-depot/PROD-metadata-pre-911-$(date +%Y%m%d-%H%M%S).tgz \
  PROD/metadata

sudo rsync -avh \
  /tmp/vcf-911-metadata/PROD/ \
  /var/www/vcf-depot/PROD/

sudo chgrp -R vcfdepot-admin /var/www/vcf-depot
sudo find /var/www/vcf-depot -type d -exec chmod 2775 {{}} \;
sudo find /var/www/vcf-depot -type f -exec chmod 664 {{}} \;

I then verified that Apache served both the PVC and its signature:

curl -k -u vcfdepot -I \
  https://vcf-depot.home.local/PROD/metadata/productVersionCatalog/v1/productVersionCatalog.json

curl -k -u vcfdepot -I \
  https://vcf-depot.home.local/PROD/metadata/productVersionCatalog/v1/productVersionCatalog.sig
HTTP/1.1 200 OK ... Content-Type: application/json HTTP/1.1 200 OK ... Content-Type: application/pgp-signature

3. The old Installer still showed only 9.1.0

The original VCF Installer already had an active offline-depot connection. I edited and saved the depot configuration again after updating the metadata. The connection stayed healthy, but Binary Management still only offered 9.1.0.0.

VCF Installer 9.1.0 showing active offline depot but only version 9.1.0.0
The existing 9.1.0 Installer still showed only 9.1.0.0 even after the depot contained the newer cumulative metadata.

At that point I deployed a fresh VCF 9.1.1 Installer from VCF-SDDC-Manager-Appliance-9.1.1.0.25713928.ova. This was the right place to test the 9.1.1 release metadata.

4. The VCF 9.1.1 UI rejected a known-good depot URL

The 9.1.1 Installer presents the offline depot as a full URL field. I entered the same HTTPS endpoint that was already proven to work:

https://vcf-depot.home.local

The UI rejected it immediately:

VCF Installer 9.1.1 Offline Depot dialog rejecting https://vcf-depot.home.local as an invalid URL
VCF Installer 9.1.1 rejected the known-good HTTPS depot URL with “The offline depot URL should be a valid URL without query parameters or fragments.”

I tested the obvious variations:

  • https://vcf-depot.home.local
  • https://vcf-depot.home.local/
  • https://vcf-depot.home.local:443/

All produced the same validation error.

The new Installer also had to trust my self-signed depot certificate, so I imported the depot certificate into the appliance trust store and rebooted. That was still worth doing, but it did not change this error. The message was being generated before any meaningful depot connection attempt.

Key clue:If the same “invalid URL” error appears before and after TLS trust is fixed, and before the depot receives a request, stop troubleshooting Apache, DNS, credentials and certificates. The URL is being rejected by validation logic first.

5. Prove whether the problem is the browser or the backend

Rather than guessing, I authenticated directly to the VCF Installer API. The local Installer API uses admin@local to generate an access token.

Create a token

read -s -p "admin@local password: " ADMINPASS
echo

AUTH_RESPONSE=$(
  jq -n \
    --arg username "admin@local" \
    --arg password "$ADMINPASS" \
    '{{username:$username,password:$password}}' |
  curl -sk \
    -H 'Content-Type: application/json' \
    -H 'Accept: application/json' \
    -X POST \
    https://localhost/v1/tokens \
    -d @-
)

unset ADMINPASS
TOKEN=$(echo "$AUTH_RESPONSE" | jq -r '.accessToken // empty')

echo "Token length: ${{#TOKEN}}"
printf '%s' "$TOKEN" | awk -F. '{{print "JWT parts:",NF}}'
Token length: 2264 JWT parts: 3

Check the current depot configuration

curl -sk \
  https://localhost/v1/system/settings/depot \
  -H "Authorization: Bearer $TOKEN" |
jq
{}

Try the URL-style API payload

This was an important test. If the web UI was the only problem, the API might accept the same URL. It did not.

read -s -p "vcfdepot password: " DEPOTPASS
echo

jq -n \
  --arg username "vcfdepot" \
  --arg password "$DEPOTPASS" \
  --arg url "https://vcf-depot.home.local/" \
  '{{
    offlineAccount: {{
      username: $username,
      password: $password
    }},
    depotConfiguration: {{
      isOfflineDepot: true,
      url: $url
    }}
  }}' > /tmp/depot-url.json

unset DEPOTPASS

curl -sk -i \
  -X PUT \
  https://localhost/v1/system/settings/depot \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  --data-binary @/tmp/depot-url.json
HTTP/1.1 400 { "errorCode":"VMWARE_DEPOT_OFFLINE_INVALID_URL", "arguments":["https://vcf-depot.home.local/"], "message":"The offline depot URL ... specified is invalid. Reason: The offline depot URL should be a valid URL without query parameters or fragments." }

That response was the turning point. This was not just a front-end form bug; the URL-form backend validation rejected the same known-good endpoint.

6. The working API workaround: hostname + port

The same depot settings API also accepts a configuration using separate hostname and port values. That form worked immediately.

read -s -p "vcfdepot password: " DEPOTPASS
echo

jq -n \
  --arg username "vcfdepot" \
  --arg password "$DEPOTPASS" \
  '{{
    offlineAccount: {{
      username: $username,
      password: $password
    }},
    depotConfiguration: {{
      isOfflineDepot: true,
      hostname: "vcf-depot.home.local",
      port: 443
    }}
  }}' > /tmp/depot-hostport.json

unset DEPOTPASS

curl -sk -i \
  -X PUT \
  https://localhost/v1/system/settings/depot \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  --data-binary @/tmp/depot-hostport.json
HTTP/1.1 202 { "offlineAccount":{ "username":"vcfdepot", "status":"DEPOT_CONNECTION_SUCCESSFUL", "message":"Depot Status: Success" }, "depotConfiguration":{ "isOfflineDepot":true, "hostname":"vcf-depot.home.local", "port":443 } }
This is the important workaround.Nothing changed on Apache. Nothing changed in DNS. Nothing changed in the certificate. The only change was the configuration representation sent to the VCF Installer: hostname + port instead of the URL-style field.

7. Force a metadata sync

Once the depot was accepted, I manually triggered a metadata synchronization so the new Installer would ingest the current PVC and manifest.

curl -sk -i \
  -X PATCH \
  https://localhost/v1/system/settings/depot/depot-sync-info \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Accept: application/json'
HTTP/1.1 202 {"syncStatus":"SYNC_IN_PROGRESS", ...}

Then verify the sync completed:

curl -sk \
  https://localhost/v1/system/settings/depot/depot-sync-info \
  -H "Authorization: Bearer $TOKEN" |
jq
{ "syncStatus": "SYNCED", "lastSyncCompletionTimestamp": "2026-09-16T01:08:10.764710313Z" }

And verify the persisted depot configuration:

curl -sk \
  https://localhost/v1/system/settings/depot \
  -H "Authorization: Bearer $TOKEN" |
jq
{ "offlineAccount": { "username": "vcfdepot", "status": "DEPOT_CONNECTION_SUCCESSFUL", "message": "Depot Status: Success" }, "depotConfiguration": { "isOfflineDepot": true, "hostname": "vcf-depot.home.local", "port": 443 } }

8. Success: VCF 9.1.1 appears in Binary Management

After the API configuration and metadata sync, a refresh of Binary Management finally showed both releases:

VCF Installer Binary Management showing both version 9.1.0.0 and 9.1.1.0
Success: the VCF 9.1.1 Installer now sees both 9.1.0.0 and 9.1.1.0 from the same offline depot.

The Not downloaded status was expected. This was a new Installer appliance with an empty local bundle cache. The depot now knew which 9.1.1 binaries exist; the next step is to populate the required 9.1.1 component files under PROD/COMP and let the Installer download them into its own cache.

What I learned

  1. Keep the offline depot persistent and independent from the Installer. Rebuilding an Installer should not mean rebuilding your depot.
  2. Signed metadata matters. The 9.1.1 metadata ZIP supplied the PVC, signature, VCF manifest, compatibility data and vSAN HCL data needed for release discovery.
  3. Merge metadata carefully. Back up the working metadata and do not use rsync --delete against a depot that already contains binaries.
  4. A 200 for both PVC files is a fast sanity check. Verify both productVersionCatalog.json and productVersionCatalog.sig.
  5. The 9.1.1 URL validation error did not mean the depot was broken. In this lab, the URL-form configuration was rejected by the backend even though the exact same depot succeeded with the host/port API form.
  6. Do not assume the exact validator defect. I proved that URL-style validation rejected this FQDN, but I did not prove whether the trigger was .local, parsing behavior, or another 9.1.1 validation condition.
  7. Use the API to separate UI problems from service problems. The API response made it possible to distinguish URL validation from TLS, Apache, DNS and authentication issues.

Cleanup

The temporary JSON files contain credentials. Remove them when troubleshooting is complete:

rm -f /tmp/depot.json \
      /tmp/depot-url.json \
      /tmp/depot-hostport.json \
      /tmp/depot-ip.json

References

Lab testedVCF 9.1.1 Commands and screenshots in this article reflect the lab workflow described above. Validate behavior in a non-production environment before applying the workaround broadly.