{"record":{"id":"621ae49bc1334bc5","repo":"thedotmack/claude-mem","slug":"telemetry-corrupt-telemetry-json-treating-as-no","errorCode":null,"errorMessage":"Telemetry: corrupt telemetry.json; treating as no recorded consent","messagePattern":"Telemetry: corrupt telemetry\\.json; treating as no recorded consent","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/telemetry/consent.ts","lineNumber":108,"sourceCode":"}\n\n/** Absolute path of telemetry.json inside the claude-mem data dir. */\nexport function getTelemetryConfigPath(): string {\n  return join(resolveDataDir(), TELEMETRY_CONFIG_FILENAME);\n}\n\n/**\n * Reads telemetry.json from the data dir. Returns null if the file is\n * missing, corrupt, or malformed — never throws.\n */\nexport function loadTelemetryConfig(): TelemetryConfig | null {\n  let raw: Partial<TelemetryConfig> | null;\n  try {\n    raw = readJsonSafe<Partial<TelemetryConfig> | null>(getTelemetryConfigPath(), null);\n  } catch (error) {\n    // Corrupt JSON — treat as no recorded consent\n    const err = error instanceof Error ? error : new Error(String(error));\n    logger.warn('SYSTEM', 'Telemetry: corrupt telemetry.json; treating as no recorded consent', undefined, err);\n    return null;\n  }\n  if (!raw || typeof raw !== 'object') return null;\n  if (typeof raw.installId !== 'string') return null;\n  // enabled may be absent (no decision recorded — default applies), but a\n  // present non-boolean value means the file is malformed.\n  if (raw.enabled !== undefined && typeof raw.enabled !== 'boolean') return null;\n  return {\n    enabled: raw.enabled,\n    installId: raw.installId,\n    decidedAt: typeof raw.decidedAt === 'string' ? raw.decidedAt : '',\n  };\n}\n\nexport function saveTelemetryConfig(config: TelemetryConfig): void {\n  const dataDir = resolveDataDir();\n  mkdirSync(dataDir, { recursive: true });\n  writeFileSync(join(dataDir, TELEMETRY_CONFIG_FILENAME), JSON.stringify(config, null, 2) + '\\n');","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/e2d1df569a8f04075d40e92461128ece7cf04c82/src/services/telemetry/consent.ts#L90-L126","documentation":"loadTelemetryConfig() wraps readJsonSafe; malformed or missing JSON is already handled inside (returning null without throwing), so this catch covers IO exceptions such as EACCES/EPERM/EIO. It returns null meaning 'no recorded consent', so the default consent policy applies until a decision is (re)written. The function never throws by contract.","triggerScenarios":"telemetry.json exists but cannot be read due to filesystem permission errors or the file being locked by other software — distinct from invalid JSON, which is handled silently.","commonSituations":"File permissions changed after install; backup or AV software locking the file; the data dir migrated between users or restored from an archive.","solutions":["Restore read permission on telemetry.json in the data dir","If the file was hand-edited into invalid JSON, readJsonSafe already treats it as no-consent — fix or delete it","Re-record the consent decision in-app afterwards so future loads are clean"],"exampleFix":"// before\nconst cfg = loadTelemetryConfig();\nif (cfg?.enabled === true) startTelemetry();\n\n// after — treat null as 'no decision recorded' and persist a fresh one\nconst cfg = loadTelemetryConfig();\nif (cfg === null) {\n  const enabled = await promptForConsent();\n  persistTelemetryConfig({\n    enabled,\n    installId: ensureInstallId(),\n    decidedAt: new Date().toISOString(),\n  });\n} else if (cfg.enabled === true) {\n  startTelemetry();\n}","handlingStrategy":"fallback","validationCode":"import { readFileSync } from 'node:fs';\n\nfunction telemetryConfigReadable(path: string): boolean {\n  try {\n    JSON.parse(readFileSync(path, 'utf8'));\n    return true;\n  } catch {\n    return false;\n  }\n}","typeGuard":"function isTelemetryConfig(v: unknown): v is { enabled?: boolean; installId: string; decidedAt?: string } {\n  if (typeof v !== 'object' || v === null) return false;\n  const c = v as Record<string, unknown>;\n  if (typeof c.installId !== 'string') return false;\n  if (c.enabled !== undefined && typeof c.enabled !== 'boolean') return false;\n  return true;\n}","tryCatchPattern":null,"preventionTips":["Do not hand-edit telemetry.json; delete it to reset consent cleanly","Keep data-dir permissions stable across upgrades and user changes","Rely on loadTelemetryConfig() never throwing — always handle the null case as 'no decision recorded'"],"tags":["telemetry","consent","config-file","io-error"],"backgroundTag":"corrupt-config-file","analyzedSha":"e2d1df569a8f04075d40e92461128ece7cf04c82","analyzedAt":"2026-08-20T23:58:13.836Z","contentChangedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}