{"record":{"id":"f5fd1ed7567dbcbe","repo":"LemmyNet/lemmy","slug":"activity-is-from-before-lemmy-0-19","errorCode":null,"errorMessage":"activity is from before lemmy 0.19","messagePattern":"activity is from before lemmy 0\\.19","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/apub/send/src/send.rs","lineNumber":114,"sourceCode":"impl SendRetryTask<'_> {\n  // this function will return successfully when (a) send succeeded or (b) worker cancelled\n  // and will return an error if an internal error occurred (send errors cause an infinite loop)\n  pub async fn send_retry_loop(self) -> Result<()> {\n    let SendRetryTask {\n      activity,\n      object,\n      inbox_urls,\n      report,\n      initial_fail_count,\n      domain,\n      context,\n      stop,\n    } = self;\n    debug_assert!(!inbox_urls.is_empty());\n\n    let pool = &mut context.pool();\n    let Some(actor_apub_id) = &activity.actor_apub_id else {\n      return Err(anyhow::anyhow!(\"activity is from before lemmy 0.19\"));\n    };\n    let actor = get_actor_cached(pool, activity.actor_type, actor_apub_id)\n      .await\n      .context(\"failed getting actor instance (was it marked deleted / removed?)\")?;\n\n    let object: DummyActivity = serde_json::from_value(object.clone())?;\n    let object = WithContext::new(object, FEDERATION_CONTEXT.deref().clone());\n    let requests = SendActivityTask::prepare(&object, actor.as_ref(), inbox_urls, &context).await?;\n    for task in requests {\n      // usually only one due to shared inbox\n      tracing::debug!(\"sending out {}\", task);\n      let mut fail_count = initial_fail_count;\n      while let Err(e) = task.sign_and_send(&context).await {\n        fail_count += 1;\n        report.send(SendActivityResult::Failure {\n          fail_count,\n          // activity_id: activity.id,\n        })?;","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/LemmyNet/lemmy/blob/439734dd638a2c06a2f907beab7dcf4646e88f86/crates/apub/send/src/send.rs#L96-L132","documentation":"This error is thrown in send_retry_loop when an outgoing federated activity has no actor_apub_id. Lemmy 0.19 changed activity storage so SentActivity always records the actor's ActivityPub ID; activities persisted by older 0.18-era code lack that field, and sending them is unsupported. The loop aborts rather than sending an activity whose origin cannot be resolved.","triggerScenarios":"Calling the federation send path with a SentActivity whose actor_apub_id is None — typically an activity row created before upgrading to Lemmy 0.19 that is being retried/sent after the upgrade.","commonSituations":"Operators upgrade a Lemmy instance from 0.18 to 0.19 and the federation queue picks up leftover pre-0.19 activities in the send queue; DB migration leftovers or partial upgrade paths surface old rows with no actor AP ID.","solutions":["Clear out pre-0.19 pending federation activities (let the queue skip/fail them or purge stale rows from the activity send state)","Ensure the 0.19 migration ran fully before starting the federation send loop","Regenerate or re-send affected activities with 0.19+ code so actor_apub_id is populated","If you maintain custom federation code, always set actor_apub_id when creating SentActivity"],"exampleFix":"// before\nlet activity = SentActivity { object, .. }; // actor_apub_id left None (pre-0.19 row)\n// after\nlet activity = SentActivity { actor_apub_id: Some(actor_apub_id), object, .. }; // require actor after 0.19","handlingStrategy":"validation","validationCode":"if activity.actor_apub_id.is_none() {\n  // skip pre-0.19 activity\n  return Ok(());\n}","typeGuard":"fn has_actor(a: &SentActivity) -> bool { a.actor_apub_id.is_some() }","tryCatchPattern":null,"preventionTips":["Complete 0.19 migrations before starting the federation send loop","Purge pre-0.19 pending activities after upgrading","Always populate actor_apub_id when creating activities in custom code"],"tags":["activitypub","federation","legacy-data","lemmy"],"backgroundTag":"unsupported-operation","analyzedSha":"439734dd638a2c06a2f907beab7dcf4646e88f86","analyzedAt":"2026-09-06T11:28:35.035Z","contentChangedAt":"2026-09-06T11:28:35.035Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}