yarnpkg/yarn · error · MessageError

publishFail

Error message

publishFail

What it means

The actual PUT to the registry (publish.js:111-117) is wrapped in try/catch; any failure—network error, 4xx/5xx response, conflict, forbidden, payment required—is re-thrown as publishFail with the underlying error.message. So this error signals the HTTP publish itself failed, and the wrapped message carries the registry's reason.

Source

Thrown at src/cli/commands/publish.js:119

  };

  pkg._id = `${pkg.name}@${pkg.version}`;
  pkg.dist = pkg.dist || {};
  pkg.dist.shasum = crypto.createHash('sha1').update(buffer).digest('hex');
  pkg.dist.integrity = ssri.fromData(buffer).toString();

  const registry = String(config.getOption('registry'));
  pkg.dist.tarball = url.resolve(registry, tbURI).replace(/^https:\/\//, 'http://');

  // publish package
  try {
    await config.registries.npm.request(NpmRegistry.escapeName(pkg.name), {
      registry: pkg && pkg.publishConfig && pkg.publishConfig.registry,
      method: 'PUT',
      body: root,
    });
  } catch (error) {
    throw new MessageError(config.reporter.lang('publishFail', error.message));
  }

  await config.executeLifecycleScript('publish');
  await config.executeLifecycleScript('postpublish');
}

export async function run(config: Config, reporter: Reporter, flags: Object, args: Array<string>): Promise<void> {
  // validate arguments
  const dir = args[0] ? path.resolve(config.cwd, args[0]) : config.cwd;
  if (args.length > 1) {
    throw new MessageError(reporter.lang('tooManyArguments', 1));
  }
  if (!await fs.exists(dir)) {
    throw new MessageError(reporter.lang('unknownFolderOrTarball'));
  }

  const stat = await fs.lstat(dir);
  let publishPath = dir;

View on GitHub (pinned to c2dda503f3)

Solutions

  1. Read the wrapped message: 'EPUBLISHCONFLICT' / version exists → bump the version (e.g., `yarn version`) and retry.
  2. 403 / forbidden → verify your token has publish rights for the package scope and that you are logged in (`yarn login`).
  3. First publish of a scoped package → pass `--access public` (or set publishConfig.access).
  4. Network/5xx → wait and retry; confirm registry reachability with `curl -I <registry>`.

Example fix

# before — version 1.0.0 already on registry
$ yarn publish   # publishFail: EPUBLISHCONFLICT
# after
$ yarn version --new-version patch
$ yarn publish
Defensive patterns

Strategy: retry

Validate before calling

async function isVersionPublished(registry, name, version) {
  const res = await fetch(`${registry}/${name}`);
  if (!res.ok) return false;
  const meta = await res.json();
  return Boolean(meta.versions && meta.versions[version]);
}

Try / catch

try {
  await runYarn(['publish']);
} catch (e) {
  if (/publishFail/.test(e.message)) {
    const m = e.message;
    if (/EPUBLISHCONFLICT|already exists/i.test(m)) console.error('Bump the version first.');
    else if (/403|forbidden/i.test(m)) console.error('Token lacks publish rights.');
    else console.error('Transient publish failure; retry.');
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Re-publishing an existing version (409/EPUBLISHCONFLICT); not authenticated / no publish rights (403); scoped package needing --access on first publish; registry rate-limit or outage (5xx); offline/network break.

Common situations: Forgot to bump version before publishing; npm token lacks publish scope; first publish of a scoped package without `--access public`; corporate registry misconfiguration; transient network failures.

Related errors


AI-assisted analysis of yarnpkg/yarn@c2dda503f3 (2026-08-13). Data as JSON: /api/errors/30c6d8d419378eb6. Report an issue: GitHub.