parity(realtime): block postgres_changes listener registration after Subscribe() [from supabase-js]

Open
#321 1 comment 0 reactions 1 assignee View on GitHub

@Tr00d is already working on this.

Since Jul 3, 2026.

Assessment

This issue has not been assessed yet.

Description

area: realtime feature

SDK Parity: C# implementation needed

A change was made in `supabase-js` that needs to be implemented in this repository for SDK parity.

Reference Implementation (supabase-js)

What Changed

The `RealtimeChannel.on()` method was updated to throw an error when attempting to add a `postgres_changes` listener after calling `subscribe()`. Previously, only `presence` listeners were blocked, and only in the `joined` state. The fix:

  1. Blocks `postgres_changes` listener registration (in addition to `presence`)
  2. Blocks in both the `joining` and `joined` states (not just `joined`)
  3. Updates the error message to include the listener type and channel topic
Code Reference
// Before:
if (this.channelAdapter.isJoined() && type === REALTIME_LISTEN_TYPES.PRESENCE) {
  throw new Error('cannot add presence callbacks after joining a channel')
}

// After:
const stateCheck = this.channelAdapter.isJoined() || this.channelAdapter.isJoining()
const typeCheck =
  type === REALTIME_LISTEN_TYPES.PRESENCE || type === REALTIME_LISTEN_TYPES.POSTGRES_CHANGES

if (stateCheck && typeCheck) {
  throw new Error(`cannot add \`${type}\` callbacks for ${this.topic} after \`subscribe()\`.`)
}

Implementation Guidance

Current State in realtime-csharp

The current Register(PostgresChangesOptions) and AddPostgresChangeHandler() methods in RealtimeChannel.cs do not check the channel's subscription state:

public IRealtimeChannel Register(PostgresChangesOptions postgresChangesOptions)
{
    PostgresChangesOptions.Add(postgresChangesOptions);
    // No guard against calling after Subscribe()
}

public void AddPostgresChangeHandler(ListenType listenType, PostgresChangesHandler postgresChangeHandler)
{
    BindPostgresChangesHandler(listenType, postgresChangeHandler);
    // No guard against calling after Subscribe()
}

The channel has IsJoining and IsJoined-equivalent properties available via State.

Expected Behavior

When a user calls Register(PostgresChangesOptions) or AddPostgresChangeHandler() on a channel that is already in Joining or Joined state, the SDK should throw an InvalidOperationException with a clear error message.

Key Behaviors to Match
  • Throw InvalidOperationException when State == ChannelState.Joining || State == ChannelState.Joined
  • Error message should identify the operation and channel topic
  • Non-postgres/presence operations should not be affected
  • Registration before Subscribe() continues to work normally
Files Likely Affected
  • Realtime/RealtimeChannel.cs

Acceptance Criteria

  • Calling Register(PostgresChangesOptions) after Subscribe() throws InvalidOperationException
  • Calling AddPostgresChangeHandler() after Subscribe() throws InvalidOperationException
  • Exception is thrown in both Joining and Joined states
  • Non-postgres listeners are not affected by this guard
  • Unit tests cover the throwing cases
  • No breaking changes to registering postgres_changes before Subscribe()

Context


Generated with Claude Code /sync-sdk-parity

Dominant language
C#
Stars
701
Forks
106
Avg merge
16h 35m
Merged PRs (30d)
45

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from supabase/supabase-csharp

All issues in supabase/supabase-csharp

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.