{"record":{"id":"c0236af0d747dfa3","repo":"thedotmack/claude-mem","slug":"claude-mem-telegram-wrapup-routes-must-be-a-json-object","errorCode":null,"errorMessage":"CLAUDE_MEM_TELEGRAM_WRAPUP_ROUTES must be a JSON object","messagePattern":"CLAUDE_MEM_TELEGRAM_WRAPUP_ROUTES must be a JSON object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/integrations/TelegramWrapupNotifier.ts","lineNumber":73,"sourceCode":"    return null;\n  }\n  if (value.bot_token !== undefined && typeof value.bot_token !== 'string') {\n    return null;\n  }\n  if (value.key !== undefined && typeof value.key !== 'string') {\n    return null;\n  }\n  return {\n    chat_id: value.chat_id,\n    ...(typeof value.bot_token === 'string' ? { bot_token: value.bot_token } : {}),\n    ...(typeof value.key === 'string' ? { key: value.key } : {}),\n  };\n}\n\nexport function loadTelegramWrapupConfig(settings: SettingsDefaults): TelegramWrapupConfig {\n  const parsedRoutes: unknown = JSON.parse(settings.CLAUDE_MEM_TELEGRAM_WRAPUP_ROUTES || '{}');\n  if (!isRouteMap(parsedRoutes)) {\n    throw new Error('CLAUDE_MEM_TELEGRAM_WRAPUP_ROUTES must be a JSON object');\n  }\n\n  const routes: Record<string, TelegramWrapupRoute> = {};\n  for (const [project, routeValue] of Object.entries(parsedRoutes)) {\n    const route = toRoute(routeValue);\n    if (route) {\n      routes[project] = route;\n    }\n  }\n\n  return {\n    enabled: settings.CLAUDE_MEM_TELEGRAM_ENABLED === 'true',\n    wrapupsEnabled: settings.CLAUDE_MEM_TELEGRAM_WRAPUPS_ENABLED === 'true',\n    botToken: settings.CLAUDE_MEM_TELEGRAM_BOT_TOKEN,\n    routes,\n  };\n}\n","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/integrations/TelegramWrapupNotifier.ts#L55-L91","documentation":"loadTelegramWrapupConfig parses the CLAUDE_MEM_TELEGRAM_WRAPUP_ROUTES setting as JSON and validates it with isRouteMap before using it as a project-to-route mapping. It throws this error when the parsed value is valid JSON but not a plain object (e.g. an array, string, number, or null), since routes must be keyed by project name.","triggerScenarios":"Settings.CLAUDE_MEM_TELEGRAM_WRAPUP_ROUTES is set to JSON that parses to a non-object, such as '[{\"project\":\"x\"}]' (array), '\"abc\"' (string), '42', or 'null'. Called from the config loader during worker startup.","commonSituations":"User pastes a JSON array instead of an object into settings; a quoted string of JSON ('\"{}\"') double-encodes the value; a migration or UI writes the wrong JSON shape.","solutions":["Set CLAUDE_MEM_TELEGRAM_WRAPUP_ROUTES to a JSON object keyed by project name, e.g. {\"myproject\":{\"chatId\":\"123\",\"token\":\"...\"}}.","Validate locally with JSON.parse and check typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed) before saving the setting.","If the value is empty or unusable, unset it entirely — the code defaults to '{}' when the setting is empty."],"exampleFix":"// before\nCLAUDE_MEM_TELEGRAM_WRAPUP_ROUTES=[{\"project\":\"app\"}]\n// after\nCLAUDE_MEM_TELEGRAM_WRAPUP_ROUTES={\"app\":{\"chatId\":\"123456\",\"token\":\"bot-token\"}}","handlingStrategy":"validation","validationCode":"const parsed = JSON.parse(raw || '{}');\nif (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n  throw new Error('CLAUDE_MEM_TELEGRAM_WRAPUP_ROUTES must be a JSON object');\n}","typeGuard":"function isRouteMap(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  config = loadTelegramWrapupConfig(settings);\n} catch (err) {\n  logger.error('Invalid TELEGRAM_WRAPUP_ROUTES, disabling wrapup notifier', err);\n  config = { routes: {} };\n}","preventionTips":["Validate the JSON shape in the settings UI before saving.","Test settings values by parsing them in a scratch script.","Never wrap the object in extra quotes (no double-encoded JSON)."],"tags":["config","json","validation"],"backgroundTag":"invalid-config-value","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}