Publishing to Marketplace
Complete guide for publishing your VS Code extension.
Prerequisites
- Publisher account at marketplace.visualstudio.com/manage
- Personal Access Token (PAT) from Azure DevOps
- vsce CLI installed:
npm install -g @vscode/vsce
Creating a Publisher
- Go to marketplace.visualstudio.com/manage
- Sign in with Microsoft account
- Click "Create publisher"
- Fill in:
- ID: Unique identifier (used in extension ID)
- Name: Display name
- Description: Optional
Getting Personal Access Token (PAT)
- Go to dev.azure.com
- Sign in → User Settings (top right) → Personal access tokens
- Click New Token
- Configure:
- Name: "VS Code Marketplace" (or any descriptive name)
- Organization: All accessible organizations ← Critical!
- Expiration: Pick a real future date such as
1 year. TheCustom definedfield defaults to today's date in some Azure DevOps UIs, so a token issued without changing it is valid only for the current day —vsce verify-patpasses the same day, butvsce publishfails withAccess Denied: The Personal Access Token used has expired.the moment the day rolls over. - Scopes: Click Show all scopes if
Marketplaceis hidden, then under Marketplace check Manage (preferred —Publishalone may be rejected by some publish API paths even whenverify-patsucceeds)
- Click Create and copy token immediately (shown only once)
Before publishing, verify the token against the manifest's publisher from the same terminal session that will run vsce:
npx --yes vsce verify-pat <publisher-id> -p "$env:VSCE_PAT"If verify-pat fails but VSCE_PAT exists in the User environment, reload it into the current process before retrying:
$env:VSCE_PAT = [System.Environment]::GetEnvironmentVariable("VSCE_PAT", "User")
npx --yes vsce verify-pat -p "$env:VSCE_PAT"If you control the repository workflow, prefer a wrapper script over repeating manual environment-variable recovery steps. A small PowerShell wrapper can validate the current Process VSCE_PAT first, automatically fall back to the User-scoped VSCE_PAT when VS Code is still holding an expired process value, and then forward vsce verify-pat, vsce show, or vsce publish with the resolved token. This avoids the common failure mode where the User environment is correct but VS Code child processes still inherit a stale token from the older process environment.
Publisher authorization failure is not proof that the token expired. Verify permissions for the intended publisher; switching to another authorized publisher changes the extension ID and requires approval. Then synchronize manifest, activation-test IDs and listing links.
In CI, a nonempty secret is not proof of a valid PAT. Verify publisher authorization using the job's secret without printing it. Local Process/User environment values and repository/environment secrets are separate stores: a local refresh does not repair CI. A publish=false build validates no credentials unless it explicitly runs that read-only check. On authentication failure, retain the artifact and commit/tag identity; report publication and downstream GitHub Release as blocked and request owner-side secret repair, never the token in chat.
Login and Publish
# Login (first time or when token expires)
npx @vscode/vsce login <publisher-id>
# Paste PAT when prompted
# Verify login
npx @vscode/vsce ls-publishers
# Verify the PAT used by this terminal before publish
npx --yes vsce verify-pat -p "$env:VSCE_PAT"
# Publish new version
npx @vscode/vsce publish
# Publish an already-built VSIX (prevents packaging the wrong artifact)
npx @vscode/vsce publish -i ./my-extension-1.0.0.vsix
# Resume an explicitly requested publish idempotently, not as a read-only check
npx @vscode/vsce publish -i ./my-extension-1.0.0.vsix --skip-duplicate
# Publish with version bump
npx @vscode/vsce publish minor # 0.1.0 → 0.2.0
npx @vscode/vsce publish patch # 0.1.0 → 0.1.1
vsceoption names vary by version. For an existing VSIX, prefer the documented-iinput option. If syntax must be checked, run help only in a process withoutVSCE_PAT; the help output itself can disclose the effective token, including to private tool logs.
Pre-publish Checklist
| Item | Check |
|---|---|
publisher in package.json |
Matches your publisher ID |
version |
Incremented from previous |
README.md |
Exists (lowercase!) and has content |
LICENSE |
Included |
icon |
128x128 PNG, path in package.json |
.vscodeignore |
Excludes unnecessary files |
package.json Requirements
{
"name": "my-extension",
"displayName": "My Extension",
"description": "Brief description for Marketplace",
"version": "1.0.0",
"publisher": "your-publisher-id",
"icon": "images/icon.png",
"repository": {
"type": "git",
"url": "https://github.com/user/repo"
},
"categories": ["Other"],
"keywords": ["keyword1", "keyword2"]
}Valid Categories
Programming Languages, Snippets, Linters, Themes, Debuggers,
Formatters, Keymaps, SCM Providers, Other, Extension Packs,
Language Packs, Data Science, Machine Learning, Visualization,
Notebooks, Education, Testing, AI, ChatVersion Constraints
- ✅ Valid:
1.0.0,1.2.3,0.0.1 - ❌ Invalid:
1.0.0-beta.1,1.0.0-rc1(prerelease tags rejected) - Use GitHub Releases for beta distribution instead
Inspect Package Before Publishing
# List files that will be included
npx @vscode/vsce ls
# Create VSIX without publishing (for inspection)
mkdir -p artifacts/vsix
npx @vscode/vsce package --out artifacts/vsix/my-extension-1.0.0.vsixUse the repository's release hygiene test for payload safety. Besides checking paths, compare packaged runtime, Webview JS/CSS, locales and icons with the same release build. Compare runtime manifest fields structurally, including publisher, version, engines, entry point, localization, contributions and opt-ins. Negative tests must reject same-name stale assets and wrong engine requirements; file lists alone prove neither content identity nor installability.
On a byte mismatch, report paths without dumping payloads. Normalize line endings only to diagnose formatter/checkout differences, never to waive the release gate. Build a clean checkout of the CI commit with the same locked toolchain and rerun strict comparison. If it passes, keep the original verified CI artifact; otherwise resolve the content drift before publication. Remove only the temporary checkout you created, preserving the user's working tree.
If a release test asserts the extension version inside docs or spec files (README, CHANGELOG, a FULL_SPECIFICATION-style file), bump every one of them together with package.json. A single doc lagging the package version fails the release gate even when the build itself is correct, so update the version in all asserted files before tagging.
Local Preview Packages
An unpublished local VSIX often has no repository URL or license file yet. If its README uses relative links (for example, a language switch or local image), vsce can reject packaging because it cannot rewrite those links. For a local-only preview:
New-Item -ItemType Directory -Force artifacts/vsix | Out-Null
npx --yes @vscode/vsce package `
--allow-missing-repository `
--skip-license `
--no-rewrite-relative-links `
--out artifacts/vsix/my-extension-0.0.1.vsixUse the exact options reported by the pinned vsce package --help; do not guess similar names. --no-rewrite-relative-links is safe only when every relative target is included in the VSIX. Inspect the archive and verify the README language target and each relative image exist at those exact paths; an image excluded by .vscodeignore cannot fall back to GitHub in a local preview.
Do not add Marketplace/version/install badges that imply publication before the extension exists there. Local previews can use factual static badges such as Local Preview, the declared minimum VS Code version, local-only privacy, and available languages. Once published, replace these with real Marketplace and repository links.
Packaging Runner Gotchas
- If packaging rejects versions that already have a release tag, keep its tests independent of the repository's current release state. Test the untagged-success path in a temporary Git work tree, and test tagged-version rejection separately. A test that expects the manifest's current version to be untagged passes before release and fails immediately after the tag is created.
- Create the parent directory passed to
--outbefore invokingvsce; the CLI can enumerate a valid package and still fail at the final write withENOENT. - On Windows, spawning
npx.cmddirectly from Node can fail withEINVAL. In an npm-managed project, invokeprocess.env.npm_execpaththroughprocess.execPathand usenpm exec --package=@vscode/vsce@<version-from-one-project-constant> -- vsce ...; validatenpm_execpathexists and is npm's CLI before spawning. For pnpm/yarn projects, use that manager's native exec command instead of forcing npm. - Treat the VSIX file as the completion source of truth. A quiet or truncated terminal is not success; confirm the artifact exists, has a fresh timestamp, and has a plausible size before moving to publish.
- If
vsce packageappears to hang inside a shared VS Code terminal duringvscode:prepublish, check for activenodeprocesses and the expected artifact before retrying. Do not stack repeatednpx vsce packageattempts against the same output path. - When terminal capture is unreliable, redirect package output to a log file or run the package command as a dedicated VS Code task, then remove any temporary task entries before committing.
- If prepublish already passed separately, still let
vsce packagerun its configured prepublish unless the localvsce package --helpexplicitly documents a supported skip flag. Unsupported flags such as guessed--no-prepublishare a sign to check local help rather than continue by trial and error. - Prefer
npx vsce package --out <file>over ambiguousnpm exec -- vsce package --out <file>forms. IfvscereportsInvalid version <path>, the package path was parsed as a version argument; switch runner syntax rather than changing the version. - Run
git status --shortafter packaging andvsce ls, not only before committing. Repository prepublish scripts can regenerate tracked metadata or JSON formatting; if that happens after the release commit/tag, either commit the mutation before packaging or restore and rebuild the VSIX so the artifact matches the tagged commit. - Use
gh run watchonly to wait, with temporary log capture when needed. Before publication, require the Actions API to reportcompleted/success, the expected commit SHA and successful mandatory audit/test/package steps; quiet output or a watcher exit alone is not proof. If local audits are unavailable, push the candidate commit and run authorized validation-only CI before creating a publication-triggering tag. Tag only the validated SHA and separately verify publication and public package identity. - After dependency changes, require a nonempty lockfile with public
resolvedURLs and integrity, then prove cleannpm ciand full audit pass. On managed devices that block direct public registries, use the approved quarantine proxy; never force a blocked--registryor weaken TLS. If a trusted mirror writes its own host intoresolved, change only that URL while preserving version and integrity, then test the published lockfile through the proxy. If this cannot be verified locally, use an authorized hosted CI workflow to generate and verify the lockfile; obtain approval if repository policy excludes workflows. Tag and publish only the validated commit and VSIX, without bypassing the quarantine. - Failed
npm cican leave local dependencies incomplete. If offline restore lacks a locked tarball, export that exact public-registry tarball from the verified CI run separately from the VSIX, match its bytes to the lockfile integrity, then usenpm cache add <tarball> --offlineandnpm ci --offlinewith the approved registry configuration. Verify local compilation and remove recovery copies. For artifacts under dot-directories, setinclude-hidden-files: trueonly with a narrowly allowlisted upload path andif-no-files-found: error; never enable broad hidden-directory uploads that could expose credentials. - Prefer an exact archive allowlist for small extensions, not only forbidden-pattern checks, and run it automatically after every package. Verify
extension/package.json, compiled entry points, locale bundles, icon, license, and every linked README are present whilesrc/, tests, sourcemaps, debug logs, private storage snapshots, and generator scripts are absent. Account forvscenormalizingREADME.mdtoreadme.mdand extensionLICENSEtoLICENSE.txt; pin the observed archive names.
const expected = new Set([
"extension/package.json",
"extension/out/extension.js",
]);
const actual = new Set(zipEntries);
const missing = [...expected].filter((name) => !actual.has(name));
const unexpected = [...actual].filter((name) => !expected.has(name));
if (missing.length || unexpected.length) {
throw new Error(
`VSIX payload mismatch: missing=${missing}; unexpected=${unexpected}`,
);
}Build the full expected set from the extension's actual runtime contract (manifest-derived entrypoint plus intentionally packaged assets); do not weaken the comparison to a size check or forbidden glob alone.
Isolated Install Gate
Do not treat a development-host launch as proof that the VSIX installs. After exact payload verification, install the same artifact into an isolated test profile and list extensions with versions:
await runVSCodeCommand(["--install-extension", vsix, "--force"], {
version: minimumVscodeVersion,
cachePath: testCache,
reuseMachineInstall: false,
});
const { stdout } = await runVSCodeCommand(
["--list-extensions", "--show-versions"],
{
version: minimumVscodeVersion,
cachePath: testCache,
reuseMachineInstall: false,
},
);Require the exact lowercase <publisher>.<name>@<version> line. A strong local release gate is: dependency audit → unit/Extension Host tests → package → exact ZIP verification → isolated install → behavior-scoped live smoke for changed external integrations. The live smoke must use that same VSIX in disposable user-data/extensions roots and observe the real result; a resolved command or dispatch status is insufficient when the contract requires a downstream response. Derive the VSIX filename from manifest name/version so version bumps cannot leave scripts or docs pointing to a stale artifact.
runVSCodeCommand adds isolated --user-data-dir and --extensions-dir arguments when reuseMachineInstall is false (the default). Resolve cachePath from a repository-owned disposable test root, not user input. If you bypass that helper and invoke the CLI yourself, provide both directories explicitly under that root before using --install-extension.
Post-publish Verification
- Apply the Release Completion Contract below; use read-only checks, never another publish command to prove existence.
- If an artifact audit is required, use
https://marketplace.visualstudio.com/_apis/public/gallery/publishers/<publisher>/vsextensions/<extension>/<version>/vspackage. A405fromHEADis inconclusive; download viaGETdirectly to a temporary file and inspect the actual ZIP. - Compare size and SHA256 with the local VSIX or GitHub Release asset when exact-byte provenance was required before publication. Otherwise treat additional downloads as follow-up audit, not a new completion gate.
- If a pushed release tag fails CI before publication, keep the failed tag as provenance. Fix the issue, bump to a new patch version, synchronize package/lock/changelog/spec files, and publish a new tag; do not move or reuse the pushed tag.
Local VSIX Artifact Hygiene
Store generated .vsix files under artifacts/vsix/ rather than the repository root. This keeps the root readable, makes cleanup scriptable, and reduces the chance of attaching or inspecting the wrong local file.
New-Item -ItemType Directory -Force artifacts/vsix | Out-Null
npx @vscode/vsce package --out artifacts/vsix/my-extension-1.0.0.vsix
npx @vscode/vsce publish -i ./artifacts/vsix/my-extension-1.0.0.vsixWhen you keep historical local builds, set a retention rule and prune old archives automatically. Keeping only the latest 10 local VSIX files is usually enough for rollback and spot-checking.
$vsixDir = "artifacts/vsix"
Get-ChildItem $vsixDir -Filter "my-extension-*.vsix" |
Sort-Object { [version]($_.BaseName -replace '^my-extension-', '') } -Descending |
Select-Object -Skip 10 |
Remove-Item -ForceIf the project ships multiple package variants such as a release VSIX and a dev/coexistence VSIX, keep all of them under artifacts/vsix/ except the one release artifact you intentionally attach. Apply the same hygiene checks to every variant so the smaller test build does not silently diverge from the release payload.
.vscodeignore
Minimize package size:
**
!package.json
!README.md
!LICENSE
!CHANGELOG.md
!out/**
!images/icon.png
src/**
test/**
node_modules/**
*.ts
tsconfig*.json
.github/**
.vscode/**
*.vsix
artifacts/**Updating Published Extensions
# Increment version and publish
npx @vscode/vsce publish patch
# Or manually update version first
npm version patch
npx @vscode/vsce publishUnpublishing
# Unpublish specific version
npx @vscode/vsce unpublish <publisher>.<extension> --version <version>
# Unpublish entire extension (use with caution!)
npx @vscode/vsce unpublish <publisher>.<extension>Common Errors
| Error | Cause | Fix |
|---|---|---|
Missing publisher |
No publisher in package.json | Add "publisher": "your-id" |
Personal Access Token... |
PAT invalid or expired | Regenerate PAT with correct scopes |
Access Denied... PAT used has expired |
The current VSCE_PAT value is expired, the open terminal still has an old value, the PAT was issued with Custom defined expiration defaulting to today, or the PAT lacks Marketplace > Manage scope (so verify-pat passes but publish is rejected) |
Regenerate the PAT with a real future expiration and Marketplace > Manage scope, update VSCE_PAT, reload the current process, and run vsce verify-pat before publish |
version already exists |
Same version published | Increment version number |
README not found |
File missing or wrong case | Create README.md (lowercase) |
invalid prerelease |
Version like 1.0.0-beta |
Use standard version format |
unknown option |
Local vsce version differs |
Check vsce <command> --help and use supported flags |
Release Completion Contract
When the user explicitly asks to release a VS Code extension, do not stop at a version bump, commit, or push. Treat the release as incomplete until all of these are done or explicitly blocked:
- Package the VSIX under
artifacts/vsix/. - Inspect the VSIX contents or run the repo-specific package integrity test.
- Run the Isolated Install Gate above against the generated VSIX; do not modify the normal user profile.
- Follow the repository's single publication route. For tag-triggered CI, first validate the candidate commit with an explicit non-publishing branch run, then push its matching tag and let CI publish and attach the same VSIX. Do not publish locally first and make CI collide with an existing version.
- For manual publication, publish the verified VSIX, push the matching tag and attach that VSIX to the GitHub Release; ensure the tag does not independently trigger a second publish.
- Keep manual workflow dispatch non-publishing by default and serialize runs capable of publishing the same package, including branch and tag routes. Check both the dispatch input and ref: a tag condition can override
publish=false. Never move a published tag; follow the repository's version/retry policy after failure. - Confirm the public item page is accessible and the public gallery API or
vsce show --jsonreturns the intended publisher, extension and version. Confirm the GitHub Release asset is uploaded, the tag resolves to the release commit, and the intended branch is synchronized with its remote.
Successful submission can precede Marketplace validation and public visibility. While the page or API is stale, use authenticated read-only status when available to distinguish pending validation from rejection. Use one bounded watcher with an explicit deadline and resumable status; never republish merely to check.
Once these checks and the pre-agreed quality gates pass, report publication complete and stop. Extra screenshots, repeated page loads and optional package hash comparisons are follow-up audits, not reasons to withhold completion. If a repository explicitly required exact artifact equality before publication, retain that gate; do not invent or relax gates mid-run. Update local state and task status without reopening completed verification.
If a blocker appears after the version bump, report the state separately:
Version, VSIX, Marketplace publish, Git tag, and GitHub Release.
GitHub Release After Marketplace Publish
When attaching the VSIX to a GitHub Release, pin the release to a full commit SHA if you use --target. Short SHAs can be rejected by the GitHub API.
$full = git rev-parse HEAD
gh release create v1.0.0 .\artifacts\vsix\my-extension-1.0.0.vsix --target $full --title "v1.0.0 - Release title" --notes-file .\release-notes-v1.0.0.mdIf you already calculate the VSIX checksum locally, record the size and SHA256 digest in the release notes too. GitHub Release asset metadata then becomes an independent proof of exactly which artifact was published, which is useful when Marketplace metadata is still stale right after publish.
$vsix = ".\artifacts\vsix\my-extension-1.0.0.vsix"
Get-Item $vsix | Select-Object Name, Length
Get-FileHash $vsix -Algorithm SHA256 | Select-Object HashVerify the GitHub Release and remote tag independently while Marketplace validation or metadata propagation is pending:
gh release view vX.Y.Z --json "tagName,name,url,isDraft,isPrerelease,publishedAt"
git ls-remote --tags origin vX.Y.ZRecord submission and public availability separately until the Release Completion Contract passes; do not use duplicate-safe publish as a verification command.
Marketplace URLs
- Your extensions:
https://marketplace.visualstudio.com/manage/publishers/<publisher-id> - Published extension:
https://marketplace.visualstudio.com/items?itemName=<publisher>.<extension> - Statistics: Available in manage portal after publish
PAT Security & Persistence
Persist VSCE_PAT safely (Windows)
# 1. Set for the current terminal session (type directly – never paste into chat!)
$env:VSCE_PAT = "<your-pat>"
# 2. Persist to User environment variables (survives reboots)
[Environment]::SetEnvironmentVariable("VSCE_PAT", $env:VSCE_PAT, "User")
# 3. Verify without revealing the value
if ($env:VSCE_PAT) { "present (length: $($env:VSCE_PAT.Length))" } else { "missing" }⚠️
SetEnvironmentVariabledoes not update already-open terminals. Open a new terminal (or restart VS Code) after persisting.
If a publish command still uses an expired token after you update the User environment, the current terminal probably kept the old process value. Reassign $env:VSCE_PAT from the User value in that terminal, then run verify-pat again.
If the PAT was accidentally exposed
- Revoke immediately at
dev.azure.com→ User Settings → Personal access tokens → Revoke - Generate a new token (same scopes)
- Update
VSCE_PATwith the new value
Rules
- ❌ Never paste a PAT into chat, issue comments, or commit messages
- ❌ Never echo
$env:VSCE_PAT– check existence/length only - ❌ Never run
vsce publish --helpwithVSCE_PATset; some versions print the effective PAT default even into private tool logs - ✅ Use
VSCE_PATenv var;vsce publishpicks it up automatically - ✅ Set expiry ≤ 1 year and rotate on a schedule
.vscodeignore – Recommended Exclusion Patterns
Keep the published VSIX small and free of dev-only artefacts:
# Source & config (already compiled to out/)
src/**
**/tsconfig.json
**/.eslintrc.json
**/*.map
**/*.ts
!out/**
# Dev tooling
.vscode/**
.vscode-test/**
.playwright-mcp/**
.github/**
node_modules/**
# Dev-only content (never ship to users)
docs/**
output/**
output_sessions/**
research/**
session/**
FULL_SPECIFICATION.md
AGENTS.md
# Local artifacts (exclude secondary docs only if no shipped link needs them)
artifacts/**
# Large or unnecessary assets
images/demo-animated.gif
*.vsixTip: Run
npx @vscode/vsce lsto preview exactly what will be packaged before runningvsce packageorvsce publish.
Gotcha:
vsce ls --packagePath foo.vsixdoes not enumerate entries; for packaged VSIX verification (e.g. confirmingnode_modules/**is excluded), open the VSIX as a ZIP and list every entry instead:Add-Type -AssemblyName System.IO.Compression.FileSystem $zip = [System.IO.Compression.ZipFile]::OpenRead((Resolve-Path foo.vsix)) $zip.Entries | Select-Object FullName, Length
Judging node_modules/** exclusion
Before excluding node_modules/**, confirm out/*.js only requires vscode
and Node built-ins, with no live external imports:
Select-String -Path out\*.js -Pattern 'require\("([^.][^"]+)"\)' -AllMatches
Select-String -Path out\*.js -Pattern 'import\("[^.]' # dynamic importsA dependencies entry that is only reached through a guarded dynamic import(...)
disabled in the extension host (e.g. a CLI-side SDK that exits early when
vscode is present) ships its entire transitive tree as dead weight. One real
case: @github/copilot-sdk → @github/copilot ≈ 285 MB → packaged VSIX 181 MB.
After moving the unused dep out and excluding node_modules/**, the same VSIX
dropped to ~45 KB (≈4000× smaller). Compare VSIX size against the previous
release; an unchanged-huge size usually means .vscodeignore is not actually
excluding node_modules/**.
Marketplace auto-resolves relative-path images
When the README references images by relative path (e.g. ),
the Marketplace web view and the in-VS Code extension details pane both resolve
those paths against repository.url in package.json and fetch the file from
raw.githubusercontent.com/<owner>/<repo>/<branch>/<path>. So as long as the
repository is public and the image is pushed to the default branch, you can keep it out of
the VSIX to drop multi-megabyte demo media without breaking the listing.
This auto-resolution applies to images, not to arbitrary Markdown links. If
you exclude secondary documents such as README_ja.md from the VSIX, link to
them with an absolute GitHub URL from the primary README.md instead of a
relative Markdown link to a publicly readable document.
Marketplace publication does not authorize making a private source repository
public. Private raw GitHub image URLs will not serve anonymous readers: use
public distribution assets, keep required icons in the VSIX, and provide alternate
language content on the listing or a publicly reachable page. Verify support access
as an intended user, not only as the maintainer. A private issue tracker is not a
public support channel: use an approved accessible alternative or clearly disclose
restricted access in the feedback UI and listing. Keep bugs.url, UI actions and
README destinations aligned; neither a VSIX link nor a support need authorizes a
repository visibility change.
An unchanged documentation icon may pin an earlier published asset version. Validate its publisher, extension, asset type and expected image rather than requiring the URL version to equal a not-yet-published package version. The new VSIX must still contain its own declared runtime and Activity Bar icons.
Verify VSIX integrity before publish
vsce ls validates .vscodeignore filtering, but it cannot detect a truncated
or zip-corrupt VSIX (which can happen when the package step is interrupted by
build watchers or transient I/O). Run the exact ZIP verifier and the Isolated
Install Gate above before vsce publish; never install release-test artifacts
into the normal user profile. A ZIP parser error such as End of central directory record signature not found means the artifact is truncated and must be rebuilt.
Also treat vsce package completion based on the output file (size +
mtime), not on console messages — terminal capture sometimes drops the
DONE Packaged: ... line, but the artifact on disk is the source of truth.
If the VSIX exists but ZIP inspection fails, check whether node / vsce is
still writing the file. Once no package process remains, delete the corrupt
artifact, rebuild with a deterministic output path, and inspect that rebuilt
file instead of reusing the partial archive.
Get-ChildItem artifacts/vsix/my-extension-1.0.0.vsix |
Select-Object Length, LastWriteTimeIf the extension manifest references icons such as icon.png for the Marketplace
tile and icon.svg for activity bar or command UI, add a release check that
asserts the referenced files physically exist before packaging.
Marketplace Propagation Notes
vsce show --jsonand the human listing can lag; do not republish solely from stale metadata.- Gallery "latest" resolution lags too, so
code --install-extension <publisher>.<name> --forceright after publish can silently install the previous version. While propagation is pending, do not install or verify by extension ID: install the identical verified local VSIX (or one downloaded from the version-specific endpoint) withcode --install-extension <path> --force, confirm withcode --list-extensions --show-versions, and do not republish. - Follow the Release Completion Contract; after the public page and exact API identity/version are confirmed, stop waiting unless a pre-agreed artifact gate is still unmet.
- If publish is paused by review, auth, duplicate, or permissions, report version, artifact checksum, commit, tag, push, and publish state separately so the same VSIX can be resumed without guessing.