Skip to content

fix: allow null contact first_name and last_name on webhook events - #140

Merged
gabrielmfern merged 1 commit into
mainfrom
feature/dev-1625-nullable-contact-names
Aug 24, 2026
Merged

fix: allow null contact first_name and last_name on webhook events#140
gabrielmfern merged 1 commit into
mainfrom
feature/dev-1625-nullable-contact-names

Conversation

@gabrielmfern

@gabrielmfern gabrielmfern commented Aug 17, 2026

Copy link
Copy Markdown
Member

The response side of this SDK is already correct: Contact.cs declares both names as string?. Only Resend.Webhooks.ContactEventData lagged, where they were:

public string FirstName { get; set; } = default!;

Nullable reference types are enabled in this project, but System.Text.Json does not enforce those annotations, so "first_name": null deserializes without throwing. The = default! then suppresses the compiler warning that would have caught it. The result is a null sitting in a property the compiler and every consumer treat as non-null, which surfaces as a NullReferenceException at the call site rather than at decode. A silent wrong answer instead of a loud failure.

Changed to string?, matching Contact.cs in the sibling package.

Not a breaking change

The diff is two lines and annotation-only:

  • No binary break. string and string? are the same runtime type, System.String. Nullability lives in NullableAttribute metadata, so the IL signature is unchanged and already-compiled consumer assemblies keep working untouched.
  • No behaviour change. Nothing about serialization or deserialization moves. A payload that decoded before decodes identically now.

The one visible effect is that consumers who read these properties into a non-nullable string will see a nullable warning (CS8600/CS8602) where they previously saw none. That warning is the point: it marks a spot where a null from the API could already have caused a NullReferenceException at runtime. Builds still succeed by default.

Payload shape, confirmed against the monorepo

These keys can be absent, null, or a string. The producer schema at packages/inngest/src/schemas/contacts.ts:104 declares firstName: z.string().nullish() (Zod for string | null | undefined), and apps/background-jobs/src/inngest/functions/webhooks/contact-events-webhook.ts:91 forwards the value to Svix uncoalesced, so undefined drops the key during serialization while null survives. The contact.created fixture in WebhookOutOfOrderTests.cs shows the absent case, with a data object carrying only id, created_at, updated_at, email, and unsubscribed.

string? collapses all three states to null, which is all C# can express, so no further distinction is needed here. The equivalent Node and Python types did need to spell out both halves.

Verification

Builds clean with 0 warnings. All 11 tests in Resend.Webhooks.Tests pass.

No test added. The existing suite has no contact-webhook null coverage to extend, and a test asserting only that a nullable property accepts null would restate the type. Say the word if you want one.

Related

Spec fix in resend/resend-openapi#91.

Ref DEV-1625

Version bump

Sets Directory.Build.props to 0.9.1. That value had drifted badly: it read 0.7.0 while the latest tag is v0.9.0.

It is only a fallback for local builds. The published version comes from the git tag, since cicd/release.sh derives VERSION from refs/tags/v* and passes -p:Version=${VERSION} to every build, publish, and pack, which overrides the props value. So the real release still depends on tagging v0.9.1; this just stops the local default from lying.

This repo normally bumps in a separate chore: PR, so drop that commit if you would rather keep the split.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

cubic analysis

No issues found across 1 file

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Linked issue analysis

Linked issue: DEV-1625: Allow nullable contact first and last names in OpenAPI

Status Acceptance criteria Notes
Contact first_name is represented as nullable in webhook event data ContactEventData.FirstName was changed from string to string? and no longer uses default!.
Contact last_name is represented as nullable in webhook event data ContactEventData.LastName was changed from string to string? and no longer uses default!.

Auto-approved: Fixes incorrect non-nullable deserialization to match the API contract and sibling Contact.cs, making two properties nullable with JSON omit-on-null. No operational tradeoff; the change only corrects wrong behavior.

Re-trigger cubic

Approval not submitted

This repository is configured to approve as @klotty, but that approval identity is unavailable.
Reconnect or verify the approval identity in repository settings.

cubic left this as a normal review comment instead of falling back to a Cubic App approval.

@gabrielmfern
gabrielmfern marked this pull request as ready for review August 17, 2026 20:23
@gabrielmfern
gabrielmfern force-pushed the feature/dev-1625-nullable-contact-names branch from 31583fd to f861081 Compare August 17, 2026 20:26
@gabrielmfern
gabrielmfern marked this pull request as draft August 17, 2026 20:27
@gabrielmfern
gabrielmfern marked this pull request as ready for review August 18, 2026 17:23
@gabrielmfern gabrielmfern self-assigned this Aug 18, 2026
@gabrielmfern
gabrielmfern marked this pull request as draft August 18, 2026 17:47
@gabrielmfern
gabrielmfern marked this pull request as ready for review August 18, 2026 17:47
@gabrielmfern
gabrielmfern force-pushed the feature/dev-1625-nullable-contact-names branch 2 times, most recently from f95f783 to 83b2d83 Compare August 18, 2026 17:49
@gabrielmfern
gabrielmfern marked this pull request as draft August 18, 2026 17:49
@gabrielmfern
gabrielmfern marked this pull request as ready for review August 18, 2026 17:52
@gabrielmfern
gabrielmfern force-pushed the feature/dev-1625-nullable-contact-names branch from 83b2d83 to b8a6b63 Compare August 18, 2026 18:46
Both were declared string with = default!, which suppressed the nullable
warning and let a null land in a property every consumer treats as
non-null. Contact.cs in the same solution already uses string?.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gabrielmfern
gabrielmfern force-pushed the feature/dev-1625-nullable-contact-names branch from b8a6b63 to 9765238 Compare August 24, 2026 19:13
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