Skip to content

fix: Unwrap protobuf Value types in CallParticipantState.custom field#1172

Open
antondokusov wants to merge 3 commits intoGetStream:mainfrom
antondokusov:fix-call-participant-custom-field
Open

fix: Unwrap protobuf Value types in CallParticipantState.custom field#1172
antondokusov wants to merge 3 commits intoGetStream:mainfrom
antondokusov:fix-call-participant-custom-field

Conversation

@antondokusov
Copy link

@antondokusov antondokusov commented Feb 4, 2026

🎯 Goal

Fix an issue where CallParticipantState.custom field contains protobuf Value wrapper objects instead of native Dart types. This makes it difficult for developers to access custom participant data, as they need to manually unwrap each Value object to get the actual values.

The protobuf Struct type uses Value wrappers to represent dynamically-typed data, but when converting to the domain model, these should be unwrapped to native Dart types for easier consumption.

🛠 Implementation details

Changed the conversion in SfuParticipantExtension.toDomain() from:

custom: custom.fields,  // Returns PbMap<String, Value>

to:

custom: (custom.toProto3Json() as Map<String, Object?>?) ?? {},

🎨 UI Changes

N/A

🧪 Testing

This change can be tested by:

  1. Joining a call with participants that have custom data fields
  2. Accessing CallParticipantState.custom and verifying that values are native Dart types instead of protobuf Value objects
  3. Verifying that nested structures (maps and lists) are properly unwrapped

Before the fix:

final participant = call.state.value.callParticipants.first;
final customField = participant.custom['custom_field'] as String; // throws "type 'Value' is not a subtype of type 'String' in type cast"

After the fix:

final participant = call.state.value.callParticipants.first;
final customField = participant.custom['custom_field'] as String; // success

☑️Contributor Checklist

General

  • Assigned a person / code owner group (required)
  • Thread with the PR link started in a respective Slack channel (#flutter-team) (required)
  • PR is linked to the GitHub issue it resolves

☑️Reviewer Checklist

  • Sample runs & works
  • UI Changes correct (before & after images)
  • Bugs validated (bugfixes)
  • New feature tested and works
  • All code we touched has new or updated Documentation

Summary by CodeRabbit

  • Bug Fixes
    • Improved participant custom-data serialization to use a safe JSON fallback, preventing null or missing-field issues and ensuring consistent, reliable handling of participant custom fields across the system.

@antondokusov antondokusov requested a review from a team as a code owner February 4, 2026 13:21
@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d747656 and 413186c.

📒 Files selected for processing (1)
  • packages/stream_video/lib/src/sfu/data/events/sfu_event_mapper_extensions.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/stream_video/lib/src/sfu/data/events/sfu_event_mapper_extensions.dart

📝 Walkthrough

Walkthrough

Updated SfuParticipantExtension.toDomain to serialize the participant custom field using custom.toProto3Json() cast to Map<String, Object?>? with a fallback to {} instead of reading custom.fields. No other control flow or functionality changed.

Changes

Cohort / File(s) Summary
SFU Event Mapper
packages/stream_video/lib/src/sfu/data/events/sfu_event_mapper_extensions.dart
Replace custom.fields usage with custom.toProto3Json() cast to Map<String, Object?>? and fallback to {} when constructing domain object.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐰 A tiny hop, a single line—
I coax the proto into JSON fine,
Fields now come from one clear spring,
A quiet tweak, a gentle ping. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: unwrapping protobuf Value types in the CallParticipantState.custom field, which is the primary purpose of this pull request.
Description check ✅ Passed The description includes the required sections (Goal, Implementation details, Testing) with clear explanations, but the Contributor and Reviewer checklists remain unchecked.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/stream_video/lib/src/sfu/data/events/sfu_event_mapper_extensions.dart (1)

244-267: ⚠️ Potential issue | 🔴 Critical

Use toProto3Json() instead of writeToJsonMap() for converting protobuf Struct values to native Dart types.

In protobuf 6.0.0, toProto3Json() is the official, documented API for Proto3 JSON serialization and converting Struct/Value types to native Dart equivalents (String, num, bool, List, Map<String, dynamic>). While writeToJsonMap() exists and may work, it's a generic message-to-map encoder and not the intended API for this conversion.

Change line 251 to: custom: custom.toProto3Json() as Map<String, dynamic>,

@antondokusov antondokusov marked this pull request as draft February 4, 2026 14:12
@antondokusov antondokusov force-pushed the fix-call-participant-custom-field branch from 07fded6 to 6fc26c4 Compare February 4, 2026 14:22
@antondokusov antondokusov force-pushed the fix-call-participant-custom-field branch from 6fc26c4 to d747656 Compare February 4, 2026 14:37
@antondokusov antondokusov marked this pull request as ready for review February 4, 2026 14:39
@codecov
Copy link

codecov bot commented Mar 3, 2026

Codecov Report

❌ Patch coverage is 0% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 6.36%. Comparing base (eab42dd) to head (413186c).

Files with missing lines Patch % Lines
...c/sfu/data/events/sfu_event_mapper_extensions.dart 0.00% 1 Missing ⚠️
Additional details and impacted files
@@          Coverage Diff          @@
##            main   #1172   +/-   ##
=====================================
  Coverage   6.36%   6.36%           
=====================================
  Files        615     615           
  Lines      43340   43340           
=====================================
  Hits        2757    2757           
  Misses     40583   40583           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Brazol
Copy link
Contributor

Brazol commented Mar 6, 2026

Hi @antondokusov, thanks for taking the time to contribute this!

The change definitely makes sense, and ideally, it would have worked this way from the start. However, introducing it now would be a breaking change, which we’re trying to avoid.

If you’re open to spending a bit more time on it, one option would be to introduce a new field with the correct mapping while marking the existing one as deprecated. That would allow us to maintain backward compatibility for now, and we could clean it up properly in the next major release.

If you’d rather not invest more time in this, no worries at all, just let us know. We can open a separate PR building on top of your changes. Thanks again for the contribution!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants