{"record":{"id":"e37705f9c1588058","repo":"parcel-bundler/parcel","slug":"a-parcel-link-already-exists-try-parcel-link-unl","errorCode":null,"errorMessage":"A Parcel link already exists! Try `parcel-link unlink` to re-link.","messagePattern":"A Parcel link already exists! Try `parcel-link unlink` to re-link\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/parcel-link/src/link.js","lineNumber":178,"sourceCode":"      '-g, --node-modules-glob <glob>',\n      'Location where node_modules should be linked in the app.\\nCan be repeated with multiple globs.',\n      (glob, globs) => globs.concat([glob.replace(/[\"']/g, '')]),\n      ['node_modules'],\n    )\n    .action(async (packageRoot, options) => {\n      if (options.dryRun) log('Dry run...');\n      let appRoot = process.cwd();\n\n      let parcelLinkConfig;\n\n      try {\n        parcelLinkConfig = await ParcelLinkConfig.load(appRoot, {fs});\n      } catch (e) {\n        // boop!\n      }\n\n      if (parcelLinkConfig) {\n        throw new Error(\n          'A Parcel link already exists! Try `parcel-link unlink` to re-link.',\n        );\n      }\n\n      parcelLinkConfig = new ParcelLinkConfig({\n        fs,\n        appRoot,\n        packageRoot: packageRoot ?? path.join(__dirname, '../../../'),\n        namespace: options.namespace,\n        nodeModulesGlobs: options.nodeModulesGlob,\n      });\n\n      await action(parcelLinkConfig, {dryRun: options.dryRun, log});\n\n      if (!options.dryRun) await parcelLinkConfig.save();\n\n      log('🎉 Linking successful');\n    });","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/parcel-bundler/parcel/blob/59484858a1a0bcbb71f74088956bb437a2db6505/packages/dev/parcel-link/src/link.js#L160-L196","documentation":"Thrown by parcel-link's link command when an existing ParcelLinkConfig is already loaded for the current app root (appRoot = process.cwd()). The command intentionally prevents stacking two links; it tells you to unlink first. Note the loader's own error is swallowed ('// boop!'), so only a successfully loaded prior config triggers this.","triggerScenarios":"Running `parcel-link link` (or the action) in a directory where a previous `parcel-link` succeeded and wrote its config (typically a .parcel-link marker/config file that ParcelLinkConfig.load can read).","commonSituations":"Re-running parcel-link after a prior link without unlinking; switching branches where a prior link config was committed; partial cleanup that left the link config behind.","solutions":["Run `parcel-link unlink` first to remove the existing link, then re-link.","Manually remove the ParcelLinkConfig file in appRoot if unlink fails, then retry.","Confirm you are in the intended appRoot (`pwd`) — a wrong cwd can see a different app's link config.","If the prior link is stale, inspect the config and clean up node_modules symlinks before re-linking."],"exampleFix":"# before\n$ parcel-link link\n# Error: A Parcel link already exists!\n\n# after\n$ parcel-link unlink\n$ parcel-link link","handlingStrategy":"validation","validationCode":"let existing;\ntry { existing = await ParcelLinkConfig.load(appRoot, { fs }); } catch { /* none */ }\nif (existing) {\n  console.error('A link already exists; run `parcel-link unlink` first.');\n  process.exit(1);\n}","typeGuard":null,"tryCatchPattern":"try { await linkCommand(appRoot); }\ncatch (e) {\n  if (/A Parcel link already exists/.test(e.message)) {\n    await unlinkCommand(appRoot);\n    await linkCommand(appRoot);\n  } else throw e;\n}","preventionTips":["Always run `parcel-link unlink` before re-linking.","If unlink fails, manually delete the ParcelLinkConfig marker file in appRoot.","Confirm cwd is the intended appRoot before linking to avoid seeing another app's config."],"tags":["parcel-link","dev-tools","state","linking"],"backgroundTag":null,"analyzedSha":"59484858a1a0bcbb71f74088956bb437a2db6505","analyzedAt":"2026-08-13T04:06:35.925Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}