Skip to content

Bug: Moderation.Distinguish fails on ever-edited comments — RedditObject.edited is BoolValue but Reddit returns a float timestamp #283

Description

@mattbrannon

Summary

Calling comment.distinguish(true) on a comment that has ever been edited rejects with a gRPC
status-2 error from the platform, even though the distinguish/sticky is actually applied on Reddit.
The root cause is a protobuf contract mismatch: Reddit's API returns edited as false or a float
epoch timestamp
, but Devvit's RedditObject.edited is declared google.protobuf.BoolValue, so the
gateway fails to marshal the (successful) response.

Environment

  • App: confessor-mod, installed on r/confession
  • SDK: @devvit/web 0.13.6 (@devvit/protos 0.13.6; flaw still present in latest @devvit/protos 0.13.10)
  • Observed in production: 2026-07-28 ~07:07 UTC

Observed error

[remove] sticky distinguish failed: Error: 2 UNKNOWN: grpc invocation failed with status 2; proto: (line 1:182): invalid value for bool field value: 1785222440.0
    at callErrorFromStatus (/srv/index.cjs:5452:21)
    at Object.onReceiveStatus (/srv/index.cjs:6133:70)
    ...
    at GenericPluginClient.Distinguish (/srv/index.cjs:137177:93)
    at tM.distinguish (main.js:6:10378)
    at tM.distinguish (main.js:6:8096)
  code: 2,
  details: 'grpc invocation failed with status 2; proto: (line 1:182): invalid value for bool field value: 1785222440.0'

Note 1785222440.0 = 2026-07-28T07:07:20Z — the exact time the app had just edited the comment
before distinguishing it. It is the comment's edited timestamp, not anything the app passed: the
app called comment.distinguish(true) with a literal boolean, and @devvit/reddit's
Comment.distinguish sends only { id, how: 'yes', sticky: true }, which matches
DistinguishRequest (moderation_msg.d.ts:65-72). The failure is in the response path.

Root cause

Moderation.Distinguish returns JsonRedditObjects (moderation_svc.d.ts:34), whose
things[].data is RedditObject (common/common_msg.d.ts). In that message:

  • approvedAtUtc, bannedAtUtc, created, createdUtc are correctly typed as numbers, but
  • edited is declared as a bool wrapper: edited?: boolean | undefined (common_msg.d.ts:207-208),
    encoded as google.protobuf.BoolValue (common_msg.js:841-842:
    BoolValue.encode({ value: message.edited }, ...)).

Reddit's API returns edited: false for never-edited things and edited: <float epoch> for edited
things. When the gateway converts Reddit's JSON response for a distinguish call into the proto, an
edited comment's timestamp cannot unmarshal into BoolValue — hence the Go protojson error naming
the wrapper's inner field: invalid value for bool field value: 1785222440.0.

Consistent with this, the error only reproduces on the edit-then-distinguish path; distinguishing
a freshly created comment (edited: false) works.

Reproduction

const comment = await post.addComment({ text: 'hello' });
await comment.distinguish(true);            // OK — edited is false
const edited = await comment.edit({ text: 'hello (edited)' });
await edited.distinguish(true);             // throws: 2 UNKNOWN ... invalid value for bool field value: <timestamp>

Impact

  • The RPC rejects, but the distinguish is applied on Reddit — the error is raised while
    marshaling the post-action comment JSON that Reddit returned, i.e. after the action succeeded.
    Apps get a spurious failure for an operation that worked, and the model fields the SDK updates from
    the response (distinguishedBy, stickied) are never populated.
  • Affects any thing that has ever been edited (the edited timestamp is permanent), for every RPC
    whose response is JsonRedditObjects / RedditObject: Moderation.Distinguish (comments and
    posts, including undistinguish / distinguishAsAdmin) and LinksAndComments.EditCustomPost.
  • Any app that maintains a pinned/sticky bot comment by editing it in place and re-distinguishing
    will log this failure deterministically.

Expected behavior / suggested fix

RedditObject.edited should accommodate Reddit's false | float union — e.g. type it as
google.protobuf.Value, or as a double with false normalized to unset — or the gateway should
coerce edited to truthiness before marshaling the response.

Workaround in the meantime

Treat distinguish failures matching invalid value for bool field value: <number> as
likely-succeeded (optionally verify by re-fetching the comment and checking stickied /
distinguishedBy).


This bug was diagnosed and this report written by Claude (Claude Code, Anthropic), working from the app's production logs and the installed @devvit packages, at the app maintainer's request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions