{"record":{"id":"616e7608d4b0ded2","repo":"nocobase/nocobase","slug":"failed-to-extract-nocobase-skills-package-name","errorCode":null,"errorMessage":"failed to extract ${NOCOBASE_SKILLS_PACKAGE_NAME} tarball: ${message}","messagePattern":"failed to extract (.+?) tarball: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/cli/src/lib/skills-manager.ts","lineNumber":388,"sourceCode":"          packageName || '(missing package name)'\n        } instead of ${NOCOBASE_SKILLS_PACKAGE_NAME}.`,\n      );\n    }\n\n    if (targetVersion && packageVersion !== targetVersion) {\n      throw new Error(\n        `packed tarball resolved to version ${packageVersion || '(missing version)'} instead of ${targetVersion}.`,\n      );\n    }\n\n    await fsp.rm(packageDir, { recursive: true, force: true });\n    await fsp.mkdir(path.dirname(packageDir), { recursive: true });\n    await fsp.rename(extractRoot, packageDir);\n    return packageDir;\n  } catch (error: unknown) {\n    await fsp.rm(extractRoot, { recursive: true, force: true });\n    const message = error instanceof Error ? error.message : String(error);\n    throw new Error(`failed to extract ${NOCOBASE_SKILLS_PACKAGE_NAME} tarball: ${message}`);\n  }\n}\n\nasync function prepareLocalSkillsPackage(\n  globalRoot: string,\n  options: SkillsSyncOptions = {},\n  targetVersion?: string,\n): Promise<{ packageDir: string; cleanup: () => Promise<void> }> {\n  const cacheRoot = getSkillsCacheRoot(globalRoot);\n  const packageDir = getCachedSkillsPackageDir(cacheRoot);\n  const packRoot = getCachedSkillsPackRoot(cacheRoot);\n  const packageSpec = targetVersion ? `${NOCOBASE_SKILLS_PACKAGE_NAME}@${targetVersion}` : NOCOBASE_SKILLS_PACKAGE_NAME;\n  const cachedVersion = await readCachedSkillsVersion(cacheRoot);\n\n  await fsp.mkdir(cacheRoot, { recursive: true });\n\n  if (targetVersion && cachedVersion && compareVersions(cachedVersion, targetVersion) === 0) {\n    options.onProgress?.(`Using cached ${NOCOBASE_SKILLS_PACKAGE_NAME}@${targetVersion}...`);","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/nocobase/nocobase/blob/fa42722fefe44265490dff2c27d79e2882bce4fa/packages/core/cli/src/lib/skills-manager.ts#L370-L406","documentation":"Wrapper error: any failure during tarball extraction or moving the extract root into place (spawn of tar, read/parse errors, rename across devices, mkdir/rm failures) is caught, the partial extractRoot is cleaned up, and rethrown with this prefix plus the underlying message. The original cause is embedded in the message text.","triggerScenarios":"extractPackedSkillsTarball's try block throws — e.g. the .tgz is corrupt or not gzip, the tar binary is missing, fsp.rename fails across filesystems, or disk is full — after the name/version checks.","commonSituations":"Truncated/partial tarball from an interrupted pack; no `tar` available in a minimal container; /tmp on a different mount than the package dir causing EXDEV on rename; permissions issues in the cache root.","solutions":["Read the suffixed cause in the message and fix it directly (e.g. re-pack if the tarball is corrupt, install tar if missing).","Delete the skills cache/package directory and re-run the sync from scratch.","Point the cache/package directory to the same filesystem as the extraction root to avoid EXDEV rename errors.","Check free disk space and write permissions on the target directories."],"exampleFix":"// before\n// rename across devices: EXDEV\npackageDir = '/mnt/external/skills'; extractRoot = '/tmp/skills-xxx';\n// after\n// keep both on the same filesystem\npackageDir = '/tmp/cache/skills'; extractRoot = '/tmp/skills-xxx';","handlingStrategy":"try-catch","validationCode":"import { access } from 'node:fs/promises';\nawait access(tarballPath); // ensure tarball exists and is readable before extraction\n// also confirm `tar` availability in minimal containers","typeGuard":null,"tryCatchPattern":"try {\n  await prepareLocalSkillsPackage(/*...*/);\n} catch (err) {\n  if (err.message.startsWith('failed to extract')) {\n    const cause = err.message.split(': ').slice(1).join(': '); // inspect underlying cause\n    // clear cache dir and retry once\n  }\n}","preventionTips":["Ensure `tar` is installed in container images that run the sync.","Keep extraction root and package dir on the same filesystem to avoid EXDEV rename errors.","Clean the skills cache directory on repeated extraction failures.","Monitor free disk space where tarballs are unpacked."],"tags":["filesystem","packaging","extraction","cli"],"backgroundTag":"tarball-extraction-failed","analyzedSha":"fa42722fefe44265490dff2c27d79e2882bce4fa","analyzedAt":"2026-09-01T00:54:31.202Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}