{"record":{"id":"f418a353365d2c47","repo":"chenhg5/cc-connect","slug":"platform-q-not-found-for-session-q","errorCode":null,"errorMessage":"platform %q not found for session %q","messagePattern":"platform %q not found for session %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/engine.go","lineNumber":1498,"sourceCode":"\t\t\tbreak\n\t\t}\n\t}\n\t// Fallback: in multi-workspace mode the stored session key may be prefixed\n\t// with the workspace path (e.g. \"/home/user/project:slack:C123:U456\").\n\t// Search for a known platform name within the key and strip the prefix.\n\tif targetPlatform == nil {\n\t\tfor _, p := range e.platforms {\n\t\t\tneedle := \":\" + p.Name() + \":\"\n\t\t\tif idx := strings.Index(sessionKey, needle); idx >= 0 {\n\t\t\t\ttargetPlatform = p\n\t\t\t\tplatformName = p.Name()\n\t\t\t\tsessionKey = sessionKey[idx+1:] // strip workspace prefix\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tif targetPlatform == nil {\n\t\treturn fmt.Errorf(\"platform %q not found for session %q\", platformName, sessionKey)\n\t}\n\n\trc, ok := targetPlatform.(ReplyContextReconstructor)\n\tif !ok {\n\t\treturn fmt.Errorf(\"platform %q does not support proactive messaging (cron)\", platformName)\n\t}\n\n\trunSessionKey := sessionKey\n\tvar replyCtx any\n\tvar err error\n\tif !job.Mute {\n\t\tif resolver, ok := targetPlatform.(CronReplyTargetResolver); ok {\n\t\t\tresolvedSessionKey, resolvedReplyCtx, err := resolver.ResolveCronReplyTarget(sessionKey, cronRunTitle(job))\n\t\t\tif err != nil {\n\t\t\t\tif !errors.Is(err, ErrNotSupported) {\n\t\t\t\t\treturn fmt.Errorf(\"resolve cron reply target: %w\", err)\n\t\t\t\t}\n\t\t\t} else {","sourceCodeStart":1480,"sourceCodeEnd":1516,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/engine.go#L1480-L1516","documentation":"ExecuteCronJob derives the platform name from the cron job's session key (the prefix before the first ':', or a known platform name found inside the key) and looks it up among registered platforms. If no registered platform matches — the prefix is not a live platform name — the engine returns 'platform %q not found for session %q'. This means the cron job references a platform that is not configured, disabled at build time, or whose name changed.","triggerScenarios":"A CronJob whose SessionKey's platform prefix (e.g. \"feishu:...\" or \"/ws:path:slack:C123:U456\") matches no platform in e.platforms: platform not present in config.toml, excluded via build tag (e.g. no_slack) or EXCLUDE=, platform name typo, or session key created under an older config with a differently named platform.","commonSituations":"Cron jobs persisted in state survive a config edit that removes/renames the platform; selective compilation (make build EXCLUDE=discord) silently drops the platform; multi-workspace session keys whose embedded platform segment doesn't match any registered p.Name().","solutions":["Check config.toml: ensure the platform named in the session key prefix is configured and enabled.","Rebuild without the excluding build tag/EXCLUDE entry (e.g. remove no_slack from tags, drop the platform from EXCLUDE=).","Delete or re-create the stale cron job (its session key references a removed platform): use the cron listing command or clear persisted cron state.","Verify the session key format: it must contain a registered platform name (p.Name()) — fix typos like 'telegramm:...'.","If the platform was renamed across versions, update the persisted cron job's session key to the new platform name."],"exampleFix":"// before: cron job persisted for a platform no longer configured\n// config.toml\n# [[platforms]]\n# name = \"discord\"   # removed, but cron jobs still reference it\n// after: re-enable the platform or purge stale jobs\n[[platforms]]\nname = \"discord\"\n# ... then delete stale jobs: cc-connect cron list / cron rm <id>","handlingStrategy":"validation","validationCode":"// Go: validate cron job targets before persisting\nfunc validCronTarget(platforms []core.Platform, sessionKey string) bool {\n    name := sessionKey\n    if i := strings.Index(sessionKey, \":\"); i > 0 { name = sessionKey[:i] }\n    for _, p := range platforms {\n        if p.Name() == name { return true }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":"if err := engine.ExecuteCronJob(job); err != nil {\n    var notFound *fmt.Errorf\n    if strings.Contains(err.Error(), \"not found for session\") {\n        slog.Error(\"cron job references missing platform; disabling job\",\n            \"job\", job.ID, \"err\", err)\n        cronStore.Remove(job.ID)\n    }\n}","preventionTips":["When removing or renaming a platform in config.toml, purge its persisted cron jobs.","Validate the session key's platform prefix against registered platforms when creating a cron job.","Remember selective compilation: platforms excluded via build tags/EXCLUDE= cannot serve cron jobs.","Keep platform names stable across config versions, or migrate stored session keys."],"tags":["cron","platform-lookup","session-key","config"],"backgroundTag":"resource-not-found","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}