Skip to content

Piero Bosio Social Web Site Personale Logo Fediverso

Social Forum federato con il resto del mondo. Non contano le istanze, contano le persone

My hypothesis on why Lemmy is rejecting valid activities

General Discussion
10 4 47
  • I have not been able to successfully post to a Lemmy instance either as a post or a comment. A cryptic error message is returned where the error is unknown and the message is a generic message:

    {"error":"unknown","message":"data did not match any variant of untagged enum AnnouncableActivities"}

    From my logs, it seems this is happening:

    1. I make a valid ActivityPub request with the audience of a community (or cc a user).
    2. Lemmy makes an ActivityPub request back at me at /.
    3. My web site does not handle ActivityPub at /, and responds with a text/plain error message. This is default behavior in Drupal.
    4. Lemmy rejects my request with a 400 response with the error message above.

    I tested other instances by making the following get request to the root of each instance (thank you, Daniel Sternberg for maintaining curl):

    curl -v -H "Accept: application/activity+json" -H "Content-Type: application/activity+json" <url>
    • With the following results
      • Lemmy returns an Application Actor.
      • Misskey returns a 200 response in text/html.
      • Mastodon returns a 406 response in application/json.
      • NodeBB returns text/html.
      • GoToSocial returns a 406 response in application/json.
      • Mitra returns a 200 response in text/html.
      • Pixelfed returns a 200 response in text/html.
      • Peertube returns an empty 406 response.

    My hypothesis is that Lemmy is rejecting the request because I return text/plain and/or it cannot handle a response with that content type.

    To test that I am working on changing the default behavior. I will need to dynamically add a route based on system.site.page.front and return a 406 response in JSON. This is simple enough. If my hypothesis is correct, I can also make a merge request into drupal/activitypub module, which would have the same problem. If not, then I’ll need to go digging further.

  • I have not been able to successfully post to a Lemmy instance either as a post or a comment. A cryptic error message is returned where the error is unknown and the message is a generic message:

    {"error":"unknown","message":"data did not match any variant of untagged enum AnnouncableActivities"}

    From my logs, it seems this is happening:

    1. I make a valid ActivityPub request with the audience of a community (or cc a user).
    2. Lemmy makes an ActivityPub request back at me at /.
    3. My web site does not handle ActivityPub at /, and responds with a text/plain error message. This is default behavior in Drupal.
    4. Lemmy rejects my request with a 400 response with the error message above.

    I tested other instances by making the following get request to the root of each instance (thank you, Daniel Sternberg for maintaining curl):

    curl -v -H "Accept: application/activity+json" -H "Content-Type: application/activity+json" <url>
    • With the following results
      • Lemmy returns an Application Actor.
      • Misskey returns a 200 response in text/html.
      • Mastodon returns a 406 response in application/json.
      • NodeBB returns text/html.
      • GoToSocial returns a 406 response in application/json.
      • Mitra returns a 200 response in text/html.
      • Pixelfed returns a 200 response in text/html.
      • Peertube returns an empty 406 response.

    My hypothesis is that Lemmy is rejecting the request because I return text/plain and/or it cannot handle a response with that content type.

    To test that I am working on changing the default behavior. I will need to dynamically add a route based on system.site.page.front and return a 406 response in JSON. This is simple enough. If my hypothesis is correct, I can also make a merge request into drupal/activitypub module, which would have the same problem. If not, then I’ll need to go digging further.

    @mradcliffe

    >Mitra returns a 200 response in text/html.

    But it federates with Lemmy

    >data did not match any variant of untagged enum AnnouncableActivities

    Did you wrap your activity in Announce?

  • @mradcliffe

    >Mitra returns a 200 response in text/html.

    But it federates with Lemmy

    >data did not match any variant of untagged enum AnnouncableActivities

    Did you wrap your activity in Announce?

    @silverpill

    >Mitra returns a 200 response in text/html.

    But it federates with Lemmy

    My hypothesis is it's the text/plain is the problem, and that everyone else is doing something acceptable.

    Did you wrap your activity in Announce?

    Is that necessary? I could not find that in the Federation documentation. I know that Lemmy sends Announces out when it forwards activities, but to me when the documentation states

    When a user creates a new post, it is sent to the respective community as Create/Page. Editing a previously created post sends an almost identical activity, except the type being Update.

    A reply to a post, or to another comment as Create/Note

    that means I should do similarly, right?

  • I have not been able to successfully post to a Lemmy instance either as a post or a comment. A cryptic error message is returned where the error is unknown and the message is a generic message:

    {"error":"unknown","message":"data did not match any variant of untagged enum AnnouncableActivities"}

    From my logs, it seems this is happening:

    1. I make a valid ActivityPub request with the audience of a community (or cc a user).
    2. Lemmy makes an ActivityPub request back at me at /.
    3. My web site does not handle ActivityPub at /, and responds with a text/plain error message. This is default behavior in Drupal.
    4. Lemmy rejects my request with a 400 response with the error message above.

    I tested other instances by making the following get request to the root of each instance (thank you, Daniel Sternberg for maintaining curl):

    curl -v -H "Accept: application/activity+json" -H "Content-Type: application/activity+json" <url>
    • With the following results
      • Lemmy returns an Application Actor.
      • Misskey returns a 200 response in text/html.
      • Mastodon returns a 406 response in application/json.
      • NodeBB returns text/html.
      • GoToSocial returns a 406 response in application/json.
      • Mitra returns a 200 response in text/html.
      • Pixelfed returns a 200 response in text/html.
      • Peertube returns an empty 406 response.

    My hypothesis is that Lemmy is rejecting the request because I return text/plain and/or it cannot handle a response with that content type.

    To test that I am working on changing the default behavior. I will need to dynamically add a route based on system.site.page.front and return a 406 response in JSON. This is simple enough. If my hypothesis is correct, I can also make a merge request into drupal/activitypub module, which would have the same problem. If not, then I’ll need to go digging further.

    If I do need to wrap it an Announce, then I think I will need to do the following based on how it works on my end.

    1. Create my post as normal, but don’t address it to the community initially.
    2. Announce my own post making sure I address it to the community.

    I guess that might show up as me boosting my own post on some instances (tooting my own horn? Horning my own toot?), which I would feel ashamed of.

     

  • If I do need to wrap it an Announce, then I think I will need to do the following based on how it works on my end.

    1. Create my post as normal, but don’t address it to the community initially.
    2. Announce my own post making sure I address it to the community.

    I guess that might show up as me boosting my own post on some instances (tooting my own horn? Horning my own toot?), which I would feel ashamed of.

     

    mradcliffe@nokoto.org no, Lemmy doesn't check the root for an Application actor (and as you discovered, NodeBB doesn't send one either, and we federate with Lemmy fine.)

    Can you share a sample Create you're sending Lemmy? You should only need to have the group actor ID in to or cc, and probably as:Public somewhere in there too.

  • If I do need to wrap it an Announce, then I think I will need to do the following based on how it works on my end.

    1. Create my post as normal, but don’t address it to the community initially.
    2. Announce my own post making sure I address it to the community.

    I guess that might show up as me boosting my own post on some instances (tooting my own horn? Horning my own toot?), which I would feel ashamed of.

     

    @mradcliffe

    >Is that necessary? I could not find that in the Federation documentation.

    The error message says that server expects an Announce activity. But yes, group's inbox should also accept replies wrapped in Create, as well as Likes.

  • @mradcliffe

    >Is that necessary? I could not find that in the Federation documentation.

    The error message says that server expects an Announce activity. But yes, group's inbox should also accept replies wrapped in Create, as well as Likes.

    silverpill@mitra.social the group's inbox should, if the post is in local category, but what if it's a post in a remote category? It doesn't ever make it over to the remote server...

  • I have not been able to successfully post to a Lemmy instance either as a post or a comment. A cryptic error message is returned where the error is unknown and the message is a generic message:

    {"error":"unknown","message":"data did not match any variant of untagged enum AnnouncableActivities"}

    From my logs, it seems this is happening:

    1. I make a valid ActivityPub request with the audience of a community (or cc a user).
    2. Lemmy makes an ActivityPub request back at me at /.
    3. My web site does not handle ActivityPub at /, and responds with a text/plain error message. This is default behavior in Drupal.
    4. Lemmy rejects my request with a 400 response with the error message above.

    I tested other instances by making the following get request to the root of each instance (thank you, Daniel Sternberg for maintaining curl):

    curl -v -H "Accept: application/activity+json" -H "Content-Type: application/activity+json" <url>
    • With the following results
      • Lemmy returns an Application Actor.
      • Misskey returns a 200 response in text/html.
      • Mastodon returns a 406 response in application/json.
      • NodeBB returns text/html.
      • GoToSocial returns a 406 response in application/json.
      • Mitra returns a 200 response in text/html.
      • Pixelfed returns a 200 response in text/html.
      • Peertube returns an empty 406 response.

    My hypothesis is that Lemmy is rejecting the request because I return text/plain and/or it cannot handle a response with that content type.

    To test that I am working on changing the default behavior. I will need to dynamically add a route based on system.site.page.front and return a 406 response in JSON. This is simple enough. If my hypothesis is correct, I can also make a merge request into drupal/activitypub module, which would have the same problem. If not, then I’ll need to go digging further.

    Hi, I had a look at the activities sent from your account. Looks like the only problem is that you are missing a @context field. After adding that it parses just fine. What you serve from / is irrelevant, that one is completely optional.

  • Hi, I had a look at the activities sent from your account. Looks like the only problem is that you are missing a @context field. After adding that it parses just fine. What you serve from / is irrelevant, that one is completely optional.

    nutomic oh that's interesting, does Lemmy do JSON-LD validation? I didn't think it would.

  • I have not been able to successfully post to a Lemmy instance either as a post or a comment. A cryptic error message is returned where the error is unknown and the message is a generic message:

    {"error":"unknown","message":"data did not match any variant of untagged enum AnnouncableActivities"}

    From my logs, it seems this is happening:

    1. I make a valid ActivityPub request with the audience of a community (or cc a user).
    2. Lemmy makes an ActivityPub request back at me at /.
    3. My web site does not handle ActivityPub at /, and responds with a text/plain error message. This is default behavior in Drupal.
    4. Lemmy rejects my request with a 400 response with the error message above.

    I tested other instances by making the following get request to the root of each instance (thank you, Daniel Sternberg for maintaining curl):

    curl -v -H "Accept: application/activity+json" -H "Content-Type: application/activity+json" <url>
    • With the following results
      • Lemmy returns an Application Actor.
      • Misskey returns a 200 response in text/html.
      • Mastodon returns a 406 response in application/json.
      • NodeBB returns text/html.
      • GoToSocial returns a 406 response in application/json.
      • Mitra returns a 200 response in text/html.
      • Pixelfed returns a 200 response in text/html.
      • Peertube returns an empty 406 response.

    My hypothesis is that Lemmy is rejecting the request because I return text/plain and/or it cannot handle a response with that content type.

    To test that I am working on changing the default behavior. I will need to dynamically add a route based on system.site.page.front and return a 406 response in JSON. This is simple enough. If my hypothesis is correct, I can also make a merge request into drupal/activitypub module, which would have the same problem. If not, then I’ll need to go digging further.

    Actually I was wrong, there is a context so thats fine. The problem is that audience should be a simple string but you are sending an error, thats why it fails. Anyway that field is optional, so you can leave it out and put the community in to or cc instead.

    julian No but still the field is mandatory (mainly because that hasnt caused any problems so far).


Gli ultimi otto messaggi ricevuti dalla Federazione
  • @mariusor@metalhead.club That's great context; thanks!

    read more

  • @silverpill@mitra.social That makes sense. I guess I was getting a little bit spun around by the idea that the keyId is not the Actor id and thinking too hard about it.

    read more

  • @jdt the fragment in a JSON-LD document IRI has a semantic meaning that goes back to RDF: https://www.w3.org/TR/rdf11-concepts/#section-fragID

    > a secondary resource that is usually a part of, view of, defined in, or described in the primary resource, and the precise semantics depend on the set of representations that might result from a retrieval action on the primary resource.

    read more

  • @jdt You're supposed to fetch the keyId first, then fetch its owner (or controller).
    But in practice its either /main-key (GoToSocial) or fragment ID, so it is indeed possible to save a HTTP request.

    read more

  • keyId is a problem.

    Generally speaking, most Actors have a `keyId' that looks something like:

    https://enigmatick.social/user/jdt#main-key

    When an inbox POST arrives from an unknown user, we can chop off the bit including #main-key and we can pull the remaining URL as the Actor's ID.

    But some implementations decided they should use /main-key instead. That indicates that the keyId format is unreliable and not well-specified. So I switched to deferring this header check for unknown Actors deeper into my ingestion pipeline so that I could retrieve the actor string from the object being sent. That works pretty well.

    But GET requests. Like followers_synchronization. Dammit. There's no object to refer to. So we're back to parsing the keyId and hoping for meaning.

    Out of 124,007 Actors in my database, 587 do not comply with the #main-key convention.

    enigmatick=> select count(*) from actors where as_public_key->>'id' NOT LIKE '%#main-key'; count ------- 587 (1 row)

    For full coverage, I need to accommodate /main-key and #key as well

    #ActivityPub

    read more

  • @reiver I'd consider interoperating social networks to be "federated", but I know it's not a precise term. There are similar ambiguities with other commonly used terms: decentralization, server, node, instance, and so on. We have our personal definitions but find that others have a different mental model than ours. It might be interesting to have a collaborative social web glossary that captures the variations of how these terms are used.

    read more

  • @rimu@mastodon.nzoss.nz Definitely. Offloading the static assets to nginx is a big win. Varnish adds a layer of serving from memory that takes it up a notch. Like having your own Fastly pop.

    It does require some configuration nuance to be sure you aren't serving cached assets to the wrong connections (e.g., authenticated GET requests that shouldn't be shared beyond a specific session).

    read more

  • @eyeinthesky

    Only as a metaphor.

    Federation happens between servers / nodes, not between networks.

    read more
Post suggeriti
  • 0 Votes
    1 Posts
    8 Views
    honkA minimalist ActivityPub microblogging server. Like, really minimalist. And opinionated. HONK! "No attention mining. No likes, no faves, no polls, no stars, no claps, no counts."#honk #ActivityPub #servers
  • 0 Votes
    4 Posts
    26 Views
    @fox I have a Mastodon account for testing but I don't run an instance myself.Mastodon is usable but yeah I think Pleroma and Misskey are better.>entire feature set of mastodonIf you want something, open an issue.@julian
  • 0 Votes
    1 Posts
    15 Views
    We were excited to see the recent release of Ghost 6 with ActivityPub features. The Ghost team have been an active participant in our Long-form Text project. John O’Nolan, founder and CEO of Ghost.org, was kind enough to answer our questions about the software and its community.SWF: For our readers who don’t know Ghost, how would you describe the platform?JO: Ghost is an independent publishing platform for people who take writing seriously. We’re open source, non-profit, and built to give creators complete ownership of their content and their audience. We’ve helped indie publishers generate over $100 million in revenue from sustainable modern media businesses like 404Media, Platformer and Tangle News.SWF: Tell us about your user community. Can you paint a picture of them with a broad brush? What kind of people choose Ghost?JO: Ghost attracts people who care about owning their home on the internet, rather than having another profile on a social media platform. Our publishers range from solo journalists and creators, to established news outlets and large businesses. They value independence, and they’re willing to do the work to maintain control of their brand, distribution, data, and relationship with readers.SWF: What is it like to be a Ghost user in 2025? What kind of problems are your users facing today?JO: The big challenge today is the same one that’s haunted independent publishers for two decades: discovery. You can own your platform and serve your audience beautifully, but if people can’t find you, none of it matters. Email newsletters have been a solid answer, but they’re still dependent on deliverability and inbox placement. Algorithms on social platforms actively suppress links now, so sharing your work there is like shouting into a hurricane.SWF: Tell us about your experience with ActivityPub. Why did you decide to add ActivityPub support to your software?JO: Ghost has had support for delivering content by email newsletters for a number of years, and email has remained an unassailable distribution platform for publishers because it’s an open protocol. No company controls your email list except you, so it’s one of the best investments you can make. ActivityPub is now doing the same thing for social technology. It allows publishers to own and control a distribution channel that allows their work to spread and be discovered by others. For the first time, you can publish independently and grow faster than ever before.SWF: What stack is Ghost built on? What development tools does your team use?JO: Ghost is all built in modern JavaScript; mainly Node and React. Our ActivityPub service is built on Fedify, and everything we build is released under an open source MIT license. Our development tools are constantly evolving, and now more quickly than ever before with the advent of AI tools, which seem to change on a near weekly basis.SWF: What was the development process like?JO: Challenging, honestly. ActivityPub is beautifully designed but the spec leaves room for interpretation, and when you’re building something new, there’s no roadmap. Building interoperability between other platforms, who’ve all interpreted the spec in their own unique ways, has been a real challenge. The approach we took was to ship early versions as quickly as possible to beta testers so we could learn as we go, using real-world data and issues to guide our process. We’re in a good spot, now, but there’s still a lot to do!SWF: Ghost produces long-form blog posts, articles and newsletters. How was the experience adapting Ghost articles to the microblogging interfaces of Mastodon and Threads?JO: In some ways really easy, and in other ways quite tricky. We’re at a pretty early stage for long-form content on ActivityPub, and the majority of other products out there don’t necessarily have interfaces for supporting it yet. The easy part is that we can provide fallbacks, so if you’re scrolling on Mastodon you might see an article title and excerpt, with a link to read the full post – and that works pretty well! The dream, though, is to make it so you can just consume the full article within whatever app you happen to be using, and doing that requires more collaboration between different platforms to agree on how to make that possible.SWF: You’ve been an active participant in the ActivityPub community since you decided to implement the standard. Why?JO: ActivityPub is a movement as much as a technology protocol, and behind it is a group of people who all believe in making the web a weird, wonderful open place for collaboration. Getting to know those humans and being a part of that movement has been every bit as important to the success of our work as writing the code that powers our software. We’ve received incredible support from the Mastodon team, AP spec authors, and other platforms who are building ActivityPub support. Without actively participating in the community, I don’t know if we would’ve gotten as far as we have already. SWF: Ghost has implemented not only a publishing interface, but also a reading experience. Why?JO: The big difference between ActivityPub and email is that it’s a 2-way protocol. When you send an email newsletter, that’s it. You’re done. But with ActivityPub, it’s possible to achieve what – in the olden days – we fondly referred to as ‘the blogosphere’. People all over the world writing and reading each other’s work. If an email newsletter is like standing on a stage giving a keynote to an audience, participating in a network is more like mingling at the afterparty. You can’t just talk the whole time, you have to listen, too. Being successful within the context of a network has always involved following and engaging with others, as peers, so it felt really important to make sure that we brought that aspect into the product.SWF: Your reader is, frankly, one of the most interesting UIs for ActivityPub we’ve seen. Tell us about why you put the time and effort into making a beautiful reading experience for Ghost.JO: We didn’t want to just tick the “ActivityPub support” checkbox – we wanted to create something that actually feels great to use every day. The idea was to bring some of the product ideas over from RSS readers and kindles, where people currently consume long-form content, and use them as the basis for an ActivityPub-native reading experience. We experimented with multiple different approaches to try and create an experience with a mix of familiarity and novelty. People intuitively understand a list of articles and a view for opening and reading them, but then when you start to see inline replies and live notifications happening around those stories – suddenly it feels like something new and different. SWF: If people want to get a taste of the kind of content Ghost publishers produce, what are some good examples to follow?JO: Tough question! There are so many out there, and it really depends on what you’re into. The best place to start would be on ghost.org/explore – when you can browse through all sorts of different categories of creators and content, and explore the things that interest you the most. SWF: If I’m a Fediverse enthusiast, what can I do to help make Ghost 6 a success?JO: Follow Ghost publishers and engage with their content – likes, replies, reposts all help! Most importantly, help us spread the word about what’s possible when platforms collaborate rather than compete. And if you’re technical, our ActivityPub implementation is entirely open source on GitHub – contributions, bug reports, and feedback make the whole ecosystem stronger.
  • 0 Votes
    1 Posts
    11 Views
    Found out today our contract was not renewed. If you have any Drupal backend leads, send them my way please.#GetFediHired #drupal #php