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
- Read the wrapped message: 'EPUBLISHCONFLICT' / version exists → bump the version (e.g., `yarn version`) and retry.
- 403 / forbidden → verify your token has publish rights for the package scope and that you are logged in (`yarn login`).
- First publish of a scoped package → pass `--access public` (or set publishConfig.access).
- 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
- Bump the version on every publish (automate with `yarn version`).
- Verify publish rights and a valid token before releasing.
- For scoped first publishes, set `--access public` or publishConfig.access.
- Retry transient 5xx/network failures with backoff.
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
- invalidAccess
- packageNotFoundRegistry
- Unexpected audit response (Invalid JSON): ${response}
- nonInteractiveNoToken
- Don't know how to handle this file type
AI-assisted analysis of yarnpkg/yarn@c2dda503f3 (2026-08-13).
Data as JSON: /api/errors/30c6d8d419378eb6.
Report an issue: GitHub.