{"record":{"id":"fd4945caba83ad8d","repo":"vercel/turborepo","slug":"could-not-find-telemetry-config-directory","errorCode":null,"errorMessage":"Could not find telemetry config directory","messagePattern":"Could not find telemetry config directory","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/turbo-telemetry/src/utils.ts","lineNumber":21,"sourceCode":"import path from \"node:path\";\nimport { configDir } from \"dirs-next\";\nimport type { PackageInfo } from \"./events/types\";\n\nfunction buildUserAgent(packageInfo: PackageInfo): string {\n  const nodeVersion = process.version;\n  const operatingSystem = os.type();\n  const architecture = os.arch();\n\n  return `${packageInfo.name} ${packageInfo.version} ${nodeVersion} ${operatingSystem} ${architecture}`;\n}\n\nasync function defaultConfigPath() {\n  const dir = process.env.TURBO_CONFIG_DIR_PATH\n    ? process.env.TURBO_CONFIG_DIR_PATH\n    : await configDir();\n\n  if (!dir) {\n    throw new Error(\"Could not find telemetry config directory\");\n  }\n\n  return path.join(dir, \"turborepo\", \"telemetry.json\");\n}\n\nfunction oneWayHashWithSalt({ input, salt }: { input: string; salt: string }) {\n  return crypto.createHash(\"sha256\").update(`${salt}${input}`).digest(\"hex\");\n}\n\n// Exported asn an object instead of export keyword, so that these functions\n// can be mocked in tests.\nexport default {\n  buildUserAgent,\n  oneWayHashWithSalt,\n  defaultConfigPath\n};\n","sourceCodeStart":3,"sourceCodeEnd":38,"githubUrl":"https://github.com/vercel/turborepo/blob/9f94a7d215b3881942527dd526afa3fc650869d5/packages/turbo-telemetry/src/utils.ts#L3-L38","documentation":"utils.defaultConfigPath() in @turbo/telemetry computes the telemetry config path: it uses TURBO_CONFIG_DIR_PATH if set, otherwise the OS config directory via dirs-next's configDir(). If neither yields a directory (configDir returns null when XDG_CONFIG_HOME and HOME are unset on Linux, or the platform's known-folder lookup fails), it throws this error. TelemetryConfig.fromDefaultConfig catches it and returns undefined, silently disabling telemetry, so it surfaces only when defaultConfigPath is used directly.","triggerScenarios":"TURBO_CONFIG_DIR_PATH unset or empty AND configDir() returning null — typically a Linux process with both HOME and XDG_CONFIG_HOME removed from the environment, or a daemon/service running without a user session profile.","commonSituations":"Minimal Docker/CI containers that strip HOME; test runners with sanitized environments; systemd services or cron jobs without User=/environment set.","solutions":["Set TURBO_CONFIG_DIR_PATH to an existing, writable directory","Ensure HOME (and optionally XDG_CONFIG_HOME on Linux) is exported for the process","If telemetry is unwanted, set TURBO_TELEMETRY_DISABLED=1 rather than deleting HOME"],"exampleFix":"# before: no HOME, configDir() returns null\nexport TURBO_CONFIG_DIR_PATH=/root/.config\n\n# after: telemetry config resolves to /root/.config/turborepo/telemetry.json","handlingStrategy":"validation","validationCode":"function hasConfigHome(): boolean {\n  return Boolean(process.env.TURBO_CONFIG_DIR_PATH || process.env.XDG_CONFIG_HOME || process.env.HOME);\n}\n\nif (!hasConfigHome()) {\n  process.env.TURBO_CONFIG_DIR_PATH = \"/tmp/turbo-config\"; // writable fallback\n}","typeGuard":null,"tryCatchPattern":"try {\n  const path = await utils.defaultConfigPath();\n} catch (e) {\n  if (e instanceof Error && e.message === \"Could not find telemetry config directory\") {\n    // set TURBO_CONFIG_DIR_PATH and retry, or proceed without telemetry\n  } else throw e;\n}","preventionTips":["Set TURBO_CONFIG_DIR_PATH explicitly in containers, CI, and daemons","Keep HOME exported in minimal images that run node tooling","Treat telemetry as optional: failures to locate its config should never fail your build"],"tags":["telemetry","environment","home-directory","config"],"backgroundTag":"config-directory-not-found","analyzedSha":"9f94a7d215b3881942527dd526afa3fc650869d5","analyzedAt":"2026-08-16T19:47:29.531Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}