{"record":{"id":"e9caaebda5c06df8","repo":"nodejs/node","slug":"you-must-specify-a-tag-using-tag-when-publishing","errorCode":null,"errorMessage":"You must specify a tag using --tag when publishing a prerelease version.","messagePattern":"You must specify a tag using --tag when publishing a prerelease version\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"deps/npm/lib/commands/publish.js","lineNumber":131,"sourceCode":"      foregroundScripts: this.npm.config.isDefault('foreground-scripts')\n        ? true\n        : this.npm.config.get('foreground-scripts'),\n      dryRun: true,\n      prefix: this.npm.localPrefix,\n      workspaces: this.workspacePaths,\n    })\n    const pkgContents = await getContents(manifest, tarballData)\n    const logPkg = () => logTar(pkgContents, { unicode, json, key: workspace })\n\n    // The purpose of re-reading the manifest is in case it changed, so that we send the latest and greatest thing to the registry note that publishConfig might have changed as well!\n    manifest = await this.#getManifest(spec, opts, true)\n    const force = this.npm.config.get('force')\n    const isDefaultTag = this.npm.config.isDefault('tag') && !manifest.publishConfig?.tag\n\n    if (!force) {\n      const isPreRelease = Boolean(semver.parse(manifest.version).prerelease.length)\n      if (isPreRelease && isDefaultTag) {\n        throw new Error('You must specify a tag using --tag when publishing a prerelease version.')\n      }\n    }\n\n    // If we are not in JSON mode then we show the user the contents of the tarball before it is published so they can see it while their otp is pending\n    if (!json) {\n      logPkg()\n    }\n\n    const resolved = npa.resolve(manifest.name, manifest.version)\n\n    // make sure tag is valid, this will throw if invalid\n    npa(`${manifest.name}@${defaultTag}`)\n\n    const registry = npmFetch.pickRegistry(resolved, opts)\n\n    await oidc({ packageName: manifest.name, registry, opts, config: this.npm.config })\n\n    const creds = this.npm.config.getCredentialsByURI(registry)","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/npm/lib/commands/publish.js#L113-L149","documentation":"Thrown by `npm publish` when publishing a version with a SemVer prerelease tag (e.g. `1.0.0-beta.1`) while the `tag` config is still at its default (`latest`) and `--force` is not set. npm refuses to silently point `latest` at a prerelease, since that would push unstable code to users running `npm install <pkg>`.","triggerScenarios":"Running `npm publish` (or `npm stage`) where `semver.parse(manifest.version).prerelease.length > 0`, `this.npm.config.isDefault('tag')` is true, `manifest.publishConfig?.tag` is unset, and `--force` is not passed.","commonSituations":"Releasing a beta/rc/alpha from the same branch used for stable releases; CI pipelines that version packages with prerelease suffixes but do not pass `--tag`; forgetting that `publishConfig.tag` in package.json also satisfies the requirement.","solutions":["Pass an explicit dist-tag, e.g. `npm publish --tag beta` (or `next`, `rc`) so the prerelease does not claim the `latest` tag.","Set `\"publishConfig\": { \"tag\": \"beta\" }` in package.json so the default tag for this package is non-latest.","Override with `--force` only if you intentionally want the prerelease to become `latest`.","Strip the prerelease suffix from the version (publish `1.0.0` instead of `1.0.0-beta.1`)."],"exampleFix":"// before\nnpm publish   // version is 1.0.0-beta.1\n// after\nnpm publish --tag beta","handlingStrategy":"validation","validationCode":"const semver = require('semver')\nfunction distTagFor(version, publishConfigTag, cliTag) {\n  const isPre = (semver.parse(version)?.prerelease.length ?? 0) > 0\n  const tag = cliTag || publishConfigTag || 'latest'\n  if (isPre && tag === 'latest') {\n    throw new Error(`Publishing prerelease ${version} requires --tag (or publishConfig.tag). Suggested: --tag beta`)\n  }\n  return tag\n}\n// before publish:\ndistTagFor(pkg.version, pkg.publishConfig?.tag, process.env.NPM_CONFIG_TAG)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set \"publishConfig.tag\" in package.json for packages that ship prereleases.","In CI, branch on whether the version contains a prerelease segment and inject --tag accordingly.","Treat a missing --tag on a prerelease as a build failure in your release script, not a manual prompt."],"tags":["publish","semver","dist-tag","npm-cli","prerelease"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}