Skip to content

Mastodon's FeatureRequest (FEP-7aa9) is rejected with 400 Missing actor because it has no actor #1289

Description

@malkoG

Summary

Mastodon 4.6+ sends FEP-7aa9 FeatureRequest activities without an actor property. Fedify's inbox verifies the signatures and then rejects the activity with 400 Missing actor before any inbox listener runs, so a Fedify-based server cannot be added to a Mastodon "Collection".

Environment

  • @fedify/fedify 2.4.2 with @fedify/h3, Node 22
  • Sender: Mastodon 4.7.2
  • Receiver: Moim (https://moim.live), Group actors with interactionPolicy.canFeature and a .on(FeatureRequest, …) listener

What happens

A Mastodon user adds a Moim Group to a Collection. The FeatureRequest arrives HTTP-signed and LD-signed, and with debug logging Fedify shows:

[DBG] fedify.federation.inbox: Linked Data Signatures are verified.
[ERR] fedify.federation.inbox: Missing actor.
[WRN] fedify.federation.http: 'POST' '/ap/actors/hackerspub/inbox': 400

The listener is never called. Mastodon treats the 400 as final, so the item stays "pending" forever.

What Mastodon sends, and how the others read it

Mastodon (2b43d597)

Pixelfed (9edda3fa)

  • actor is optional for this one type: InboxValidator.php#L192-L195
    public static function actorOptionalFor(array $payload): bool
    {
        return isset($payload['type']) && $payload['type'] === 'FeatureRequest';
    }
    and the validator rule is 'actor' => 'sometimes|nullable|url' (FeatureRequestValidator.php#L19).
  • The requester is the HTTP-signature key owner: HandlesFeatureRequests.php#L85-L91
    /**
     * The requester. FeatureRequest usually has no `actor` property, so
     * fall back to the profile that owns the HTTP signature key. The inbox
     * validator already verified the signature against that key.
     */

@fedify/interaction-controls (fea9c751)

  • featureInteraction already handles a request without actor by taking the requester from the collection's attributedTo: packages/interaction-controls/src/feature.ts#L43-L45. That code runs inside a listener, which the core inbox never reaches for these activities.

Impact

Any Fedify app implementing the consumer side of FEP-7aa9 is unreachable from Mastodon Collections, which is where these requests come from today. Confirmed on moim.live; Hackers' Pub will hit the same thing when it implements featured actors (hackers-pub/hackerspub#422).

For now Moim runs a local pnpm patch that, for FeatureRequest only, uses the HTTP-signature key owner as the actor (moim-social/moim#183). With it the request is accepted and Mastodon receives the Accept.

AI disclosure

Per AI_POLICY.md: the investigation behind this report (reading the Mastodon, Pixelfed, and Fedify sources, reproducing the failure, and collecting the logs) and the first draft of this text were done with Claude Code (Claude Fable 5.1, claude-fable-5-1). I reviewed and verified the findings against the referenced sources and did the final editing myself.

Assisted-by: Claude Code:claude-fable-5-1

Activity

  1. self-assigned this
    on Oct 10, 2026
  2. added theissue type on Oct 10, 2026
  3. added this to the Fedify 2.5 milestone on Oct 11, 2026
  4. dahlia commented on Oct 11, 2026

    @dahlia
    Member

    The fix is now targeted for Fedify 2.5 rather than 2.4.3. PR #1291 has been closed without merging, so this bug remains unresolved and the existing actorless-request rejection remains in place.

    We initially tried a FeatureRequest-specific bridge to avoid introducing a general authentication API in a patch release. The review loop showed that safe acceptance still requires a consistent relationship between the authenticated principal, the exact JSON-LD interpretation, the collection's ownership, and queued delivery. Successive fixes addressed individual symptoms, but confirmed parsing and ownership gaps remained. We will address this issue with the shared authentication design in #1290.

    For the replacement:

    • Identify authenticated principals independently of the declared actor. A valid signature alone does not authorize a request naming someone else's collection; the requester must match the reliably resolved collection owner.
    • Distinguish an absent actor from an explicit actor that cannot be authenticated. Validate complete instrument and attributedTo values before typed parsing loses anonymous/untyped values, including list containers.
    • Use the same verified interpretation for authorization and listener delivery. Preserve the original signed payload separately, and carry that interpretation and authentication metadata through queues and retries without re-fetching mutable contexts.
    • Preserve web-origin and portable-proof checks, and distinguish malformed remote data from transient loader failures at their source. Retain Accept actorless FeatureRequest activities #1291's regression cases across HTTP Signatures, Linked Data Signatures, Object Integrity Proofs, forwarding, and queued delivery.

    #1291 is a source of test cases, not an implementation ready to merge. The independent loader scheme bug is tracked separately in #1292.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Fields

Priority

None yet

Effort

None yet

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions