Skip to content

fix: guard against null source in SingleOrDefaultIfMultiple - #147

Merged
ANcpLua merged 1 commit into
mainfrom
claude/singleordefault-null-guard
Jun 28, 2026
Merged

fix: guard against null source in SingleOrDefaultIfMultiple#147
ANcpLua merged 1 commit into
mainfrom
claude/singleordefault-null-guard

Conversation

@ANcpLua

@ANcpLua ANcpLua commented Jun 28, 2026

Copy link
Copy Markdown
Owner

SingleOrDefaultIfMultiple<T> calls source.GetEnumerator() without validating source, so passing null throws a NullReferenceException.

Every other public entry point in EnumerableExtensions.SingleOnly, Only(predicate), OnlyOrDefault, OnlyOrDefault(predicate) — routes through TryOnly, which calls Guard.NotNull(source) and throws a clean ArgumentNullException. This makes SingleOrDefaultIfMultiple the odd one out.

This adds the same Guard.NotNull(source) guard so the null-argument contract is consistent across the file. No behavior change for non-null inputs.

SingleOrDefaultIfMultiple called source.GetEnumerator() directly, so a null
argument surfaced as a NullReferenceException. Every other entry point in this
file (Only / OnlyOrDefault, via TryOnly) validates the argument with
Guard.NotNull and throws ArgumentNullException. Add the same guard so the
null-argument contract is consistent across EnumerableExtensions.Single.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0d3def77-0cfa-4edc-80fc-fcecefe6285c

📥 Commits

Reviewing files that changed from the base of the PR and between 0b4ec34 and 3819d45.

📒 Files selected for processing (1)
  • src/ANcpLua.Roslyn.Utilities/EnumerableExtensions.Single.cs
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx,cs,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Skip files whose first ~3 lines contain // Ported from <upstream>, // Generated, or // Auto-generated — surface a one-line note instead of line-level findings

Files:

  • src/ANcpLua.Roslyn.Utilities/EnumerableExtensions.Single.cs
**/*.cs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

.NET code: enable nullable reference types, use central package management via Directory.Packages.props, and treat Version.props as the single owner of versions — never edit <Version> lines directly

Files:

  • src/ANcpLua.Roslyn.Utilities/EnumerableExtensions.Single.cs
src/ANcpLua.Roslyn.Utilities/**/*.{cs,csproj}

📄 CodeRabbit inference engine (AGENTS.md)

Keep ANCPLUA_ROSLYN_PUBLIC controlled per-consumer; avoid bleeding API-visibility mode into source-only or internal package surfaces

Files:

  • src/ANcpLua.Roslyn.Utilities/EnumerableExtensions.Single.cs
src/**/*.cs

📄 CodeRabbit inference engine (Custom checks)

src/**/*.cs: In C# public async methods, verify that every async method accepts and forwards a CancellationToken parameter
When adding a new injectable service class registered in dependency injection, verify that it registers an ActivitySource or Meter for OpenTelemetry instrumentation

Files:

  • src/ANcpLua.Roslyn.Utilities/EnumerableExtensions.Single.cs

⚙️ CodeRabbit configuration file

src/**/*.cs: C# 14 / .NET 10 codebase. Review for: idiomatic modern C#, proper async/await (no sync-over-async, no fire-and-forget without justification), correct IDisposable/IAsyncDisposable, null safety (NRTs enabled), and adherence to existing patterns. Flag new public API surface that lacks XML doc comments. Check DI lifetime correctness (scoped vs singleton vs transient).
ARCHITECTURAL INVARIANTS — flag violations as blocking: 1. Every new injectable service must register OpenTelemetry instrumentation
(ActivitySource or Meter).
2. Every new DuckDB write path must handle backpressure (bounded channel or semaphore). 3. No hardcoded connection strings, paths, or magic strings — use IOptions or
IConfiguration.
4. No new dependencies on Sentry-specific types in core/ — Sentry is a comparison
target, not an identity.
5. CancellationToken must be threaded through all async public methods. 6. No sync-over-async (.Result, .GetAwaiter().GetResult()) outside of
well-documented infrastructure code.

Files:

  • src/ANcpLua.Roslyn.Utilities/EnumerableExtensions.Single.cs
src/**/*.{cs,js,ts,py}

📄 CodeRabbit inference engine (Custom checks)

When adding new code paths that write to DuckDB, verify it uses a bounded channel or semaphore for backpressure handling

Files:

  • src/ANcpLua.Roslyn.Utilities/EnumerableExtensions.Single.cs
**

⚙️ CodeRabbit configuration file

**: # ANcpLua.Roslyn.Utilities

Minimal navigation for Claude/Codex agents. Keep policy in AGENTS.md; keep findings in issues, PRs, or tests.

Project Index

  1. AOT reflection generator
  2. AOT reflection attributes
  3. Discriminated union generator
  4. Extensible enum mirror generator
  5. Core Roslyn utilities
  6. Polyfills package
  7. Source-only package
  8. Testing utilities
  9. AOT testing utilities

Nearby Repos

  • ANcpLua.NET.Sdk: shared SDK/version truth for the ANcpLua repos.
  • ANcpLua.Analyzers: analyzer consumer of the source-only utilities.
  • ANcpLua.Agents: successor location for agent workflow/test helpers; do not describe this repo as the MAF runtime home.

**:

999.9.9


10.0.203
latestMinor

<PropertyGroup Label="Roslyn">
    <RoslynVersion>5.3.0</RoslynVersion>
    <RoslynAnalyzersVersion>5.3.0</RoslynAnalyzersVersion>
</PropertyGroup>

<!-- ═══════════════════════════════════════════════════════════════════════
     ROSLYN ANALYZER TESTING
     Used by: Roslyn.Utilities.Testing, Analyzers.Tests
     ════════════════════════════════════════════════════════════════════...

Files:

  • src/ANcpLua.Roslyn.Utilities/EnumerableExtensions.Single.cs
src/ANcpLua.Roslyn.Utilities/**

⚙️ CodeRabbit configuration file

src/ANcpLua.Roslyn.Utilities/**: # ANcpLua.Roslyn.Utilities

Core runtime and Roslyn utility package.

  • Project: ANcpLua.Roslyn.Utilities.csproj
  • Runtime helpers should stay usable without Roslyn dependencies where possible.
  • Check existing helper types before adding another abstraction.

Files:

  • src/ANcpLua.Roslyn.Utilities/EnumerableExtensions.Single.cs
🔇 Additional comments (1)
src/ANcpLua.Roslyn.Utilities/EnumerableExtensions.Single.cs (1)

26-27: LGTM!


Summary by CodeRabbit

  • Bug Fixes
    • Improved input validation for a sequence helper so null values are handled immediately with a clear guard check instead of failing later during processing.

Walkthrough

Adds a Guard.NotNull(source) call at the top of SingleOrDefaultIfMultiple<T> in EnumerableExtensions.Single.cs to explicitly validate the source parameter before enumeration begins.

Null Guard Addition

Layer / File(s) Summary
Null guard enforcement
src/ANcpLua.Roslyn.Utilities/EnumerableExtensions.Single.cs
Guard.NotNull(source) inserted before GetEnumerator() so null input throws eagerly with a clear error instead of a deferred NullReferenceException.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Title check ❌ Error The title matches the change, but it violates the required conventional-commit scope format. Use a title like fix(<scope>): guard against null source in SingleOrDefaultIfMultiple with one of the required scopes.
✅ Passed checks (7 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly matches the null-guard fix in SingleOrDefaultIfMultiple.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Otel Instrumentation Required ✅ Passed Only a static EnumerableExtensions file changed; no new DI-registered service class, ActivitySource, or Meter was added.
No Unbounded Mcp Responses ✅ Passed No src/qyl.mcp paths or MCP tool definitions exist in this PR, so the bounded-response check is not applicable.
Duckdb Backpressure On Write Paths ✅ Passed The PR only adds a null guard in EnumerableExtensions.Single.cs; no new DuckDB write path is introduced.
Cancellationtoken Threading ✅ Passed No new public async methods were added; the only modified method is synchronous and only adds a null guard.

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

@ANcpLua
ANcpLua merged commit dfece50 into main Jun 28, 2026
7 checks passed
@ANcpLua
ANcpLua deleted the claude/singleordefault-null-guard branch June 28, 2026 20:11
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.

1 participant