paperclipai/paperclip · error

Managed install metadata is missing.

Error message

Managed install metadata is missing.

What it means

Thrown by updateCommand on the managed-npm update path when readInstallManifest returned null. By this point the mode is 'managed' (so the executable resolves through the store's current symlink) but no manifest.json exists, meaning the store is in an inconsistent state: a working symlink without the metadata needed to compute the next manifest, channel, or previous[] history.

Source

Thrown at cli/src/commands/update.ts:244

      try {
        fs.writeFileSync(npmUserConfigPath, `registry=${PUBLIC_NPM_REGISTRY}\n@paperclipai:registry=${PUBLIC_NPM_REGISTRY}\n`, { mode: 0o600 });
        await runCommand("npm", args, {
          env: {
            ...process.env,
            npm_config_registry: PUBLIC_NPM_REGISTRY,
            NPM_CONFIG_REGISTRY: PUBLIC_NPM_REGISTRY,
            npm_config_userconfig: npmUserConfigPath,
            NPM_CONFIG_USERCONFIG: npmUserConfigPath,
          },
          maxBuffer: 16 * 1024 * 1024,
        });
      } finally {
        fs.rmSync(npmConfigDir, { recursive: true, force: true });
      }
    }
    emit(options, { mode, action: "update", targetVersion, dryRun: Boolean(options.dryRun), command: ["npm", ...args] }, options.dryRun ? "Dry run complete." : pc.green(`Updated global npm install to ${targetVersion}.`)); return;
  }
  if (!manifest) throw new Error("Managed install metadata is missing.");
  if (comparison === 0) { emit(options, { mode, currentVersion, targetVersion, changed: false }, `paperclipai ${targetVersion} is already active.`); return; }
  if (comparison < 0 && options.yes !== true) { const confirmed = await (overrides.confirm ?? defaultConfirm)(`Downgrade paperclipai from ${currentVersion} to ${targetVersion}?`); if (!confirmed) throw new Error("Downgrade cancelled. Re-run with --yes to confirm explicitly."); }
  if (options.dryRun) { emit(options, { mode, currentVersion, targetVersion, action: comparison < 0 ? "downgrade" : "update", backup: options.backup !== false, dryRun: true }, `Would ${comparison < 0 ? "downgrade" : "update"} paperclipai ${currentVersion} → ${targetVersion}${options.backup === false ? " without a backup" : " after a database backup"}.`); return; }
  if (options.backup !== false) await runPreUpdateBackup(options, overrides.backup ?? (() => dbBackupCommand({})), overrides.hasInstanceData);
  const installed = await withInstallStoreLock(async () => {
    const payload = await installNpmPayload(targetVersion, runCommand, paths);
    const record: InstallRecord = { source: "npm", version: targetVersion, channel: request.channel, payloadPath: payload.payloadPath, installedAt: (overrides.now?.() ?? new Date()).toISOString() };
    const next = buildNextManifest(record, manifest); const oldTarget = fs.readlinkSync(paths.currentPath); flipCurrentAtomic(payload.payloadPath, paths);
    try { writeInstallManifestAtomic(next, paths); } catch (error) { flipCurrentAtomic(path.resolve(paths.cliRoot, oldTarget), paths); throw error; }
    pruneInstallPayloads(next, paths); return payload;
  }, paths);
  let restarted: boolean;
  try {
    restarted = await (overrides.restartActiveService ?? restartActiveManagedService)(targetVersion);
  } catch (error) {
    return rollbackAfterServiceValidationFailure(
      paths,
      overrides.restartActiveService ?? restartActiveManagedService,

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Reinstall cleanly: remove the broken store directory and run `paperclipai install` to regenerate both the symlink and manifest.
  2. Restore manifest.json from a backup into the managed install store root.
  3. If only the manifest is missing and the payload dir is intact, write a minimal manifest (source, version, channel, payloadPath, previous: []) matching the current symlink target.
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';
import { resolveInstallStorePaths, readInstallManifest } from '../install-store.js';
function managedStoreConsistent(): boolean {
  const paths = resolveInstallStorePaths();
  return fs.existsSync(paths.cliRoot) && readInstallManifest(paths) !== null;
}
// if (!managedStoreConsistent()) { /* reinstall before update */ }

Try / catch

try {
  await updateCommand(options);
} catch (error) {
  if (error instanceof Error && error.message === 'Managed install metadata is missing.') {
    // store is inconsistent — reinstall to regenerate manifest, then retry update
    await installCommand(/* ... */);
    await updateCommand(options);
  } else throw error;
}

Prevention

When it happens

Trigger: updateCommand reaches line 244 in managed mode with a null manifest — e.g. the current symlink exists but manifest.json was deleted, or the store was partially reconstructed. Distinct from error 184 which fires inside rollbackManagedInstall; this one fires on the forward-update path.

Common situations: Manifest file removed/renamed by accident. Store migrated/copied without manifest.json. A prior failed update that wrote the symlink but not the manifest. Hand-edited store leaving it inconsistent.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/2c77a31a36ae117d. Report an issue: GitHub.