tinyhumansai/openhuman · error · Error

Post deletion was not accepted by the backend

Error message

Post deletion was not accepted by the backend

What it means

Thrown when the post-delete confirm flow calls apiClient.feeds.deletePost(post.postId) and it resolves with { ok: false } - the backend refused the deletion even though the request went through. Unlike the comment path, the happy path then chains a homeFeed refetch with pagination reset (offset: 0) because the mutation invalidates offsets; on ok:false that refetch never runs and the .catch only logs, so the post stays visible.

Source

Thrown at app/src/agentworld/pages/FeedSection.tsx:899

    }
  };

  // ── Delete post ────────────────────────────────────────────────────────────

  // Open the in-app confirm modal; the actual delete runs in `confirmDeletePost`
  // only after the user confirms (replaces the native window.confirm — #4197).
  const handleDeletePost = (post: GqlPost) => {
    setPostPendingDelete(post);
  };

  const confirmDeletePost = () => {
    const post = postPendingDelete;
    if (!post) return;
    setDeletingPost(true);
    void apiClient.feeds
      .deletePost(post.postId)
      .then(({ ok }) => {
        if (!ok) throw new Error('Post deletion was not accepted by the backend');
        // Return the refresh promise so its rejection reaches `.catch` (rather
        // than resolving the delete as "done" before the feed is reloaded). A
        // mutation invalidates offsets, so reset pagination to the first page.
        return apiClient.graphql
          .homeFeed({ limit: FEED_PAGE_SIZE, offset: 0, includeSelf: true })
          .then(result => {
            setFeedState(firstPageFeedState(result));
          });
      })
      .catch(err => console.error('[FeedSection] delete post failed:', err))
      .finally(() => {
        setDeletingPost(false);
        setPostPendingDelete(null);
      });
  };

  // ── Refetch feed ───────────────────────────────────────────────────────────

View on GitHub (pinned to 7491200858)

Solutions

  1. Reload the feed from the first page and retry only if the post is still present
  2. Check that the user is the post author (or has moderation rights) for that feed
  3. Inspect the deletePost response body in the network tab for a refusal reason
  4. Mirror the comment path: on failure still trigger a feed refresh so the UI converges with the backend, and surface a toast

Example fix

// before
.then(({ ok }) => {
  if (!ok) throw new Error('Post deletion was not accepted by the backend');
  return apiClient.graphql.homeFeed({ limit: FEED_PAGE_SIZE, offset: 0, includeSelf: true })...
})
.catch(err => console.error('[FeedSection] delete post failed:', err));

// after - always resync after settling so a refused delete drops stale posts
.catch(err => {
  console.error('[FeedSection] delete post failed:', err);
  setDeleteError(err instanceof Error ? err.message : String(err));
  apiClient.graphql
    .homeFeed({ limit: FEED_PAGE_SIZE, offset: 0, includeSelf: true })
    .then(result => setFeedState(firstPageFeedState(result)))
    .catch(refreshErr => console.error('[FeedSection] resync failed:', refreshErr));
});
Defensive patterns

Strategy: try-catch

Validate before calling

// Only offer delete for posts the user authored (or can moderate) and that
// are still present in the current feed page.
const canDelete = post.author.handle === currentHandle && feedHasPost(post.postId);

Try / catch

void apiClient.feeds.deletePost(post.postId)
  .then(({ ok }) => {
    if (!ok) throw new Error('Post deletion was not accepted by the backend');
    return apiClient.graphql.homeFeed({ limit: FEED_PAGE_SIZE, offset: 0, includeSelf: true });
  })
  .then(result => setFeedState(firstPageFeedState(result)))
  .catch(err => {
    console.error('[FeedSection] delete post failed:', err);
    setDeleteError(err instanceof Error ? err.message : String(err));
    // still resync from page 0 - the mutation may have partially applied
    apiClient.graphql.homeFeed({ limit: FEED_PAGE_SIZE, offset: 0, includeSelf: true })
      .then(result => setFeedState(firstPageFeedState(result)))
      .catch(() => {});
  });

Prevention

When it happens

Trigger: User confirms post deletion in the feed and the backend answers ok:false - post already deleted elsewhere, actor not the author / lacking delete permission, or post.postId from a stale feed page that no longer exists server-side.

Common situations: Multiple sessions on the same feed; feed state stale after reconnect or thread switch; permission revocation on the backend between render and delete; soft-failure (200 + ok:false) backend convention hiding the refusal from the user.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/a66d3c715bb0c3ef. Report an issue: GitHub.