{"record":{"id":"d2bf9eca51526eb6","repo":"paperclipai/paperclip","slug":"invalid-migrator-lockfile-entry","errorCode":null,"errorMessage":"Invalid migrator lockfile entry.","messagePattern":"Invalid migrator lockfile entry\\.","errorType":"console","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/cloud-migrator-artifacts.mjs","lineNumber":51,"sourceCode":"export function assertManifest(manifest, sha) {\n  if (manifest?.version !== 1 || manifest.sourceSha !== sha || manifest.packageVersion !== versionFor(sha)) throw new Error(\"Artifact source identity mismatch.\");\n  for (const name of names) assertDescriptor(manifest.packages?.[name], \"tgz\");\n  assertDescriptor(manifest.lockfile, \"json\");\n}\n\nexport function assertLockfile(lock, manifest) {\n  const version = manifest.packageVersion;\n  if (lock?.lockfileVersion !== 3 || !lock.packages || Array.isArray(lock.packages) ||\n      JSON.stringify(lock.packages[\"\"]?.dependencies) !== JSON.stringify({ \"@paperclipai/db\": version })) throw new Error(\"Invalid migrator lockfile root.\");\n  for (const name of names) {\n    const pin = lock.packages[`node_modules/@paperclipai/${name}`];\n    const expected = manifest.packages[name];\n    if (pin?.version !== version || pin.integrity !== expected.integrity || pin.resolved !== expected.url || pin.link || pin.inBundle) throw new Error(\"Migrator lockfile package pin mismatch.\");\n  }\n  if (lock.packages[\"node_modules/@paperclipai/db\"].dependencies?.[\"@paperclipai/shared\"] !== version) throw new Error(\"Migrator shared dependency mismatch.\");\n  for (const [key, entry] of Object.entries(lock.packages)) {\n    if (key === \"\") continue;\n    if (!entry || typeof entry !== \"object\" || entry.link) throw new Error(\"Invalid migrator lockfile entry.\");\n    if (/(?:^|\\/)node_modules\\/@paperclipai\\/[^/]+$/.test(key) && !names.some((name) => key === `node_modules/@paperclipai/${name}`)) throw new Error(\"Unexpected internal migrator dependency.\");\n    if (entry.inBundle === true) {\n      if (!key.startsWith(\"node_modules/@paperclipai/db/node_modules/\")) throw new Error(\"Unexpected bundled dependency.\");\n      continue;\n    }\n    if (!/^sha512-[A-Za-z0-9+/]{86}==$/.test(entry.integrity ?? \"\")) throw new Error(\"Migrator dependency has no strong integrity pin.\");\n    if (names.some((name) => key === `node_modules/@paperclipai/${name}`)) continue;\n    const url = new URL(entry.resolved);\n    if (url.origin !== \"https://registry.npmjs.org\" || url.username || url.password || url.search || url.hash) throw new Error(\"Migrator dependency must resolve to npm.\");\n  }\n}\n\nexport function buildBundle(directory, sha, { exec = execFileSync } = {}) {\n  versionFor(sha);\n  directory = path.resolve(directory);\n  const packages = {};\n  for (const name of names) {\n    const bytes = readFileSync(path.join(directory, `${name}.tgz`));","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/scripts/cloud-migrator-artifacts.mjs#L33-L69","documentation":"Every non-root lockfile entry must be a well-formed package object and must not be a link (entry.link truthy). This error means a packages[] entry is null, not an object, or is a filesystem link entry, so its provenance cannot be verified. The validator refuses any entry it cannot pin by integrity.","triggerScenarios":"assertLockfile(lock, manifest) iterates lock.packages and hits an entry that is null/undefined/a non-object, or one with a truthy link property (e.g. a file: or workspace link entry npm recorded).","commonSituations":"Installing with workspaces or file: link dependencies so npm emits link entries in the lockfile; a corrupted or truncated package-lock.json; a hand-merged lockfile leaving a null entry.","solutions":["Remove link/file: dependency styles from the migrator install root and rebuild so npm produces real registry/tarball entries","Regenerate the lockfile with the `build` command instead of hand-editing package-lock.json","Validate the lockfile JSON is not truncated or merge-corrupted (JSON.parse + inspect packages entries)"],"exampleFix":"// before\n\"node_modules/foo\": { \"link\": true, \"resolved\": \"packages/foo\" }\n// after (rebuild without link deps)\n\"node_modules/foo\": { \"version\": \"1.2.3\", \"resolved\": \"https://registry.npmjs.org/foo/-/foo-1.2.3.tgz\", \"integrity\": \"sha512-...\" }","handlingStrategy":"validation","validationCode":"for (const [key, entry] of Object.entries(lock.packages ?? {})) {\n  if (key === \"\") continue;\n  if (!entry || typeof entry !== \"object\" || entry.link) throw new Error(`bad lockfile entry: ${key}`);\n}","typeGuard":"const isSolidEntry = (entry) => !!entry && typeof entry === \"object\" && !entry.link;","tryCatchPattern":"try {\n  assertLockfile(lock, manifest);\n} catch (err) {\n  if (err.message === \"Invalid migrator lockfile entry.\") {\n    // find and report the offending key\n    for (const [k, e] of Object.entries(lock.packages)) if (!e || typeof e !== \"object\" || e.link) console.error(`offending entry: ${k}`);\n  }\n  throw err;\n}","preventionTips":["Avoid file:/workspace link dependencies in the migrator install root","Never hand-merge package-lock.json files; regenerate instead","JSON.parse the lockfile and sanity-check entries before validating","Keep lockfileVersion 3 (modern npm) so entry shapes are uniform"],"tags":["lockfile","validation","supply-chain"],"backgroundTag":"schema-validation-failed","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}