Skip to content

RG-T117 Chatbox fixes - #451

Merged
ucswift merged 2 commits into
masterfrom
develop
Aug 8, 2026
Merged

RG-T117 Chatbox fixes#451
ucswift merged 2 commits into
masterfrom
develop

Conversation

@ucswift

@ucswift ucswift commented Aug 8, 2026

Copy link
Copy Markdown
Member

Pull Request Description

RG-T117: Chatbox Fixes

This PR addresses data validation and input handling issues in the Chatbox feature that were causing database errors, along with a related date validation fix in the Calls API.

Changes

Chatbot Settings Input Validation

  • Added server-side length validation in ChatbotDepartmentConfigService that checks string fields against database column sizes before saving, preventing SQL truncation errors (error 8152)
  • Added StringLength data annotation validators to the ChatbotSettingsModel for AllowedPlatforms, LlmApiEndpoint, LlmModelName, and LlmApiKey fields
  • Added maxlength attributes and inline validation message spans to the chatbot settings form inputs for immediate client-side feedback
  • Updated the ChatbotSettingsController to properly handle invalid model state by re-loading the existing API key indicator before returning the view with errors

Calls API Date Validation

  • Added input validation to the GetCalls endpoint to reject missing or invalid date parameters that bind to DateTime.MinValue, which falls below SQL Server's datetime floor (1753-01-01) and causes a SqlDateTime overflow exception at the repository layer
  • Added validation ensuring endDate is not earlier than startDate
  • Returns a 400 BadRequest with a descriptive message when validation fails

Impact

These changes prevent unhandled database exceptions when users submit chatbot configuration with overly long values or when API consumers omit date parameters, replacing them with clear, user-friendly validation errors.

Summary by CodeRabbit

  • Bug Fixes
    • Added validation for chatbot settings, including platform, endpoint, model, and API key length limits.
    • Blocked invalid or unsafe LLM endpoints and prevented saving invalid configurations.
    • Improved API responses for invalid chatbot settings with descriptive errors.
    • Added validation for call date ranges and unsupported dates, returning clear bad-request messages.
    • Preserved API key status when chatbot settings contain validation errors.
    • Added field-level validation messages and input limits to the chatbot settings form.

@Resgrid-Bot

This comment has been minimized.

@request-info

request-info Bot commented Aug 8, 2026

Copy link
Copy Markdown

Thanks for opening this, but we'd appreciate a little more information. Could you update it with more details?

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds chatbot settings validation across the model, view, controller, and configuration service. It also adds UTF-8 byte validation, API error mapping, an NLU project reference, and date validation to GetCalls.

Changes

Chatbot settings validation

Layer / File(s) Summary
Chatbot settings input validation
Web/Resgrid.Web/Areas/User/Models/ChatbotSettingsModel.cs, Web/Resgrid.Web/Attributes/MaxUtf8BytesAttribute.cs, Web/Resgrid.Web/Areas/User/Views/ChatbotSettings/Index.cshtml, Web/Resgrid.Web/Areas/User/Controllers/ChatbotSettingsController.cs, Web/Resgrid.Web/Resgrid.Web.csproj
Chatbot settings now enforce character and UTF-8 byte limits, validate nonblank endpoints, display validation messages, and preserve the existing API-key indicator when validation fails.
Configuration persistence validation
Core/Resgrid.Chatbot/Services/ChatbotDepartmentConfigService.cs, Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs
The service validates field and encrypted API-key lengths before saving. The API maps ArgumentException to HTTP 400 responses.

Calls date validation

Layer / File(s) Summary
Calls request date validation
Web/Resgrid.Web.Services/Controllers/v4/CallsController.cs
GetCalls now returns BadRequest for dates before SQL Server’s minimum date and for reversed date ranges.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • Resgrid/Core#412: Both PRs modify chatbot configuration handling and ChatbotController; this PR adds validation and error handling.

Suggested reviewers: github-actions

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately identifies the chatbot fixes, which are a significant part of the changes, but it does not mention the Calls API date validation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

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.

/// </summary>
private static void ValidateColumnLengths(ChatbotDepartmentConfig config)
{
if (config.AllowedPlatforms != null && config.AllowedPlatforms.Length > 500)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules low

Magic number obscures the inline column-size limit of 500, violating Rule [9] by breaking explicit schema contracts. Extract this literal to a private const (e.g., MaxAllowedPlatformsLength) for the length check and error message, and apply the same fix to CallsController.cs:1710 and lines 166, 169, and 172 of ChatbotDepartmentConfigService.cs.

Kody rule violation: Replace magic numbers with named constants

Prompt for LLM

File Core/Resgrid.Chatbot/Services/ChatbotDepartmentConfigService.cs:

Line 163:

Magic number obscures the inline column-size limit of 500, violating Rule [9] by breaking explicit schema contracts. Extract this literal to a private const (e.g., `MaxAllowedPlatformsLength`) for the length check and error message, and apply the same fix to `CallsController.cs:1710` and lines 166, 169, and 172 of `ChatbotDepartmentConfigService.cs`.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.


if (!ModelState.IsValid)
{
var existing = await _chatbotConfigService.GetConfigAsync(DepartmentId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules high

Unguarded async operation occurs because the awaited call to GetConfigAsync on line 60 falls outside the try/catch block, violating Rule [1]. Wrap this await in error handling or move the ModelState branch inside the existing try block to log and handle exceptions with context.

Kody rule violation: Handle async operations with proper error handling

Prompt for LLM

File Web/Resgrid.Web/Areas/User/Controllers/ChatbotSettingsController.cs:

Line 60:

Unguarded async operation occurs because the awaited call to `GetConfigAsync` on line 60 falls outside the try/catch block, violating Rule [1]. Wrap this await in error handling or move the `ModelState` branch inside the existing try block to log and handle exceptions with context.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.


if (!ModelState.IsValid)
{
var existing = await _chatbotConfigService.GetConfigAsync(DepartmentId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules high

Unguarded external call on line 60 leaves GetConfigAsync exposed to unhandled exceptions, violating Rule [27]. Enclose this call in a try/catch block to log contextual data (DepartmentId) and map the error to a fallback view or application-level exception.

Kody rule violation: Add try-catch blocks for external calls

Prompt for LLM

File Web/Resgrid.Web/Areas/User/Controllers/ChatbotSettingsController.cs:

Line 60:

Unguarded external call on line 60 leaves `GetConfigAsync` exposed to unhandled exceptions, violating Rule [27]. Enclose this call in a try/catch block to log contextual data (`DepartmentId`) and map the error to a fallback view or application-level exception.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Core/Resgrid.Chatbot/Services/ChatbotDepartmentConfigService.cs`:
- Around line 156-173: Update ValidateColumnLengths and the ChatbotController
exception handling so oversized configuration fields produce a typed validation
failure that is mapped to BadRequest (HTTP 400) before the generic exception
handler. Preserve the existing HTTP 500 behavior for unrelated exceptions and
apply the validation path to AllowedPlatforms, LlmApiEndpoint, LlmModelName, and
encrypted LlmApiKey.

In `@Web/Resgrid.Web/Areas/User/Models/ChatbotSettingsModel.cs`:
- Around line 30-31: Update the user-settings save flow in
ChatbotSettingsController.Index to validate request.LlmApiEndpoint with the
existing LlmEndpointValidator.IsValid check before copying it into
ChatbotDepartmentConfig or calling SaveConfigAsync. Reuse the same validation
arguments and invalid-input handling as the other API/LLM configuration writer,
or place the check in a shared boundary covering both writers.
- Around line 36-40: Update the validation for the write-only API-key property
in ChatbotSettingsModel so the limit is based on the UTF-8 byte length required
by encryption rather than character count, ensuring encrypted values remain
within the 1000-character LlmApiKey column. Preserve the existing write-only and
HasLlmApiKey behavior while applying validation consistently to Unicode input.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2518004e-c7be-4836-9d3a-3f6b9c8158be

📥 Commits

Reviewing files that changed from the base of the PR and between 8f95f5a and e07e672.

📒 Files selected for processing (5)
  • Core/Resgrid.Chatbot/Services/ChatbotDepartmentConfigService.cs
  • Web/Resgrid.Web.Services/Controllers/v4/CallsController.cs
  • Web/Resgrid.Web/Areas/User/Controllers/ChatbotSettingsController.cs
  • Web/Resgrid.Web/Areas/User/Models/ChatbotSettingsModel.cs
  • Web/Resgrid.Web/Areas/User/Views/ChatbotSettings/Index.cshtml

Comment on lines +156 to +173
/// <summary>
/// Guards against SQL truncation (error 8152) by validating string fields against the
/// ChatbotDepartmentConfigs column sizes (M0068/M0070) before hitting the database.
/// LlmApiKey is checked post-encryption since the ciphertext is what gets stored.
/// </summary>
private static void ValidateColumnLengths(ChatbotDepartmentConfig config)
{
if (config.AllowedPlatforms != null && config.AllowedPlatforms.Length > 500)
throw new ArgumentException("AllowedPlatforms cannot exceed 500 characters.", nameof(config));

if (config.LlmApiEndpoint != null && config.LlmApiEndpoint.Length > 500)
throw new ArgumentException("LlmApiEndpoint cannot exceed 500 characters.", nameof(config));

if (config.LlmModelName != null && config.LlmModelName.Length > 200)
throw new ArgumentException("LlmModelName cannot exceed 200 characters.", nameof(config));

if (config.LlmApiKey != null && config.LlmApiKey.Length > 1000)
throw new ArgumentException("Encrypted LlmApiKey cannot exceed 1000 characters; supply a shorter API key.", nameof(config));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Map configuration validation failures to HTTP 400.

ValidateColumnLengths throws ArgumentException for request data. Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs catches every exception and returns HTTP 500. An oversized AllowedPlatforms, LlmApiEndpoint, LlmModelName, or API key is therefore reported as a server failure instead of a client validation error.

Use a typed validation exception or a shared validation result. Map it to BadRequest before the generic exception handler.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/Resgrid.Chatbot/Services/ChatbotDepartmentConfigService.cs` around lines
156 - 173, Update ValidateColumnLengths and the ChatbotController exception
handling so oversized configuration fields produce a typed validation failure
that is mapped to BadRequest (HTTP 400) before the generic exception handler.
Preserve the existing HTTP 500 behavior for unrelated exceptions and apply the
validation path to AllowedPlatforms, LlmApiEndpoint, LlmModelName, and encrypted
LlmApiKey.

Comment thread Web/Resgrid.Web/Areas/User/Models/ChatbotSettingsModel.cs
Comment thread Web/Resgrid.Web/Areas/User/Models/ChatbotSettingsModel.cs
@Resgrid-Bot

Resgrid-Bot commented Aug 8, 2026

Copy link
Copy Markdown

Code Review Completed! 🔥

The code review was successfully completed based on your current configurations.

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug
Performance
Security
Business Logic

Access your configuration settings here.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
Web/Resgrid.Web/Areas/User/Controllers/ChatbotSettingsController.cs (1)

63-69: 🩺 Stability & Availability | 🟠 Major

Guard the configuration reload on invalid model state.

Line 65 calls GetConfigAsync before the try block. A configuration-service failure can escape the action and turn an invalid submission into an unhandled 500. Move this branch into handled error flow or add local error handling. Keep model.LlmApiKey cleared on every return path.

This repeats the earlier review finding for the same unguarded reload.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Web/Resgrid.Web/Areas/User/Controllers/ChatbotSettingsController.cs` around
lines 63 - 69, Update the invalid-ModelState branch in the relevant action of
ChatbotSettingsController so GetConfigAsync is executed within the existing
handled error flow or protected by local error handling. Preserve clearing
model.LlmApiKey on every return path, including configuration-service failure,
while retaining the existing validation response behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs`:
- Around line 305-309: Narrow the ArgumentException handling in
ChatbotController.UpdateConfig() so authorization and DTO validation failures
cannot be converted to HTTP 400 responses. Perform column-length config
validation explicitly before SaveConfigAsync(), then wrap only SaveConfigAsync()
if its ArgumentException contract must remain; return a stable client-safe
message instead of ex.Message, while preserving downstream failure propagation.

---

Outside diff comments:
In `@Web/Resgrid.Web/Areas/User/Controllers/ChatbotSettingsController.cs`:
- Around line 63-69: Update the invalid-ModelState branch in the relevant action
of ChatbotSettingsController so GetConfigAsync is executed within the existing
handled error flow or protected by local error handling. Preserve clearing
model.LlmApiKey on every return path, including configuration-service failure,
while retaining the existing validation response behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: dbe8af30-7560-40bb-976a-359309916068

📥 Commits

Reviewing files that changed from the base of the PR and between e07e672 and 02e4fa7.

📒 Files selected for processing (6)
  • Core/Resgrid.Chatbot/Services/ChatbotDepartmentConfigService.cs
  • Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs
  • Web/Resgrid.Web/Areas/User/Controllers/ChatbotSettingsController.cs
  • Web/Resgrid.Web/Areas/User/Models/ChatbotSettingsModel.cs
  • Web/Resgrid.Web/Attributes/MaxUtf8BytesAttribute.cs
  • Web/Resgrid.Web/Resgrid.Web.csproj
🚧 Files skipped from review as they are similar to previous changes (2)
  • Web/Resgrid.Web/Areas/User/Models/ChatbotSettingsModel.cs
  • Core/Resgrid.Chatbot/Services/ChatbotDepartmentConfigService.cs

Comment on lines +305 to +309
catch (ArgumentException ex)
{
// Field-length (column size) validation from the config service.
return BadRequest(new { error = ex.Message });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -nP -C 8 \
  'throw\s+new\s+ArgumentException|catch\s*\(\s*ArgumentException|SaveConfigAsync' \
  --glob '*.cs' . || true

Repository: Resgrid/Core

Length of output: 50369


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- target file location ---\n'
git ls-files | rg 'Web/Resgrid.Web.Services/Controllers/v4/ChatbotController\.cs$|ChatbotController\.cs$' || true

printf '\n--- ChatbotController outline ---\n'
ast-grep outline 'Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs' --view compact || true

printf '\n--- UpdateConfig and SaveConfigAsync sections ---\n'
rg -n -C 12 'UpdateConfig|SaveConfigAsync|ArgumentException|try|catch'Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs || true

printf '\n--- save-config service/repository implementations ---\n'
rg -n -C 8 'SaveConfigAsync|UpdateConfig\(\)' --glob '**/*.cs' . | sed -n '1,220p' || true

Repository: Resgrid/Core

Length of output: 241


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- target file location ---'
git ls-files | rg 'Web/Resgrid.Web.Services/Controllers/v4/ChatbotController\.cs$|ChatbotController\.cs$' || true

printf '%s\n' ''
printf '%s\n' '--- ChatbotController outline ---'
ast-grep outline 'Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs' --view compact || true

printf '%s\n' ''
printf '%s\n' '--- UpdateConfig and SaveConfigAsync sections ---'
rg -n -C 12 'UpdateConfig|SaveConfigAsync|ArgumentException|try|catch' 'Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs' || true

printf '%s\n' ''
printf '%s\n' '--- save-config service/repository implementations ---'
rg -n -C 8 'SaveConfigAsync|UpdateConfig\(\)' --glob '**/*.cs' . | sed -n '1,220p' || true

Repository: Resgrid/Core

Length of output: 25542


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- ChatbotDepartmentConfigService SaveConfigAsync ---'
sed -n '100,155p' 'Core/Resgrid.Chatbot/Services/ChatbotDepartmentConfigService.cs'

printf '%s\n' ''
printf '%s\n' '--- repo Save implementation candidates ---'
rg -n -C 10 'class .*DepartmentConfig|SaveConfigAsync|UpdateAsync\(.*ChatbotDepartmentConfig' --glob '**/*.cs' . | sed -n '1,260p' || true

printf '%s\n' ''
printf '%s\n' '--- precise repository/implementation files ---'
git ls-files | rg 'Chatbot.*Config.*Repository|DepartmentConfig.*Repository|\bRepository.*\.cs$' | rg -i 'chatbot|config' || true

Repository: Resgrid/Core

Length of output: 27268


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- ValidateColumnLengths implementation ---'
rg -n -C 25 'ValidateColumnLengths|class ChatbotDepartmentConfigService' 'Core/Resgrid.Chatbot/Services/ChatbotDepartmentConfigService.cs' || true

printf '%s\n' ''
printf '%s\n' '--- Repository method bodies ---'
sed -n '20,220p' 'Repositories/Resgrid.Repositories.DataRepository/ChatbotDepartmentConfigRepository.cs' || true

Repository: Resgrid/Core

Length of output: 4936


Narrow the ArgumentException handling to config validation only.

ChatbotController.UpdateConfig() wraps authorization, DTO validation, and SaveConfigAsync() in a single try. SaveConfigAsync() also catches and rethrows downstream failures, so the broad catch can return authorization/repository failures as HTTP 400 with internal exception text. Move column-length validation to an explicit 400 condition before saving, wrap only SaveConfigAsync() in a narrow ArgumentException block if it keeps that contract, or introduce a dedicated config-validation exception type. Return a stable client-safe message in the 400 path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs` around lines
305 - 309, Narrow the ArgumentException handling in
ChatbotController.UpdateConfig() so authorization and DTO validation failures
cannot be converted to HTTP 400 responses. Perform column-length config
validation explicitly before SaveConfigAsync(), then wrap only SaveConfigAsync()
if its ArgumentException contract must remain; return a stable client-safe
message instead of ex.Message, while preserving downstream failure propagation.

Source: Coding guidelines

Comment on lines +305 to +309
catch (ArgumentException ex)
{
// Field-length (column size) validation from the config service.
return BadRequest(new { error = ex.Message });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Bug high

Overly broad exception handling in the catch (ArgumentException ex) block captures internal server errors from _encryptionService.Encrypt() where Rfc2898DeriveBytes throws ArgumentNullException for invalid encryption salts. Introduce a dedicated ColumnLengthValidationException thrown by ValidateColumnLengths and catch only that specific type to ensure genuine ArgumentExceptions fall through to catch(Exception).

// Throw a dedicated ColumnLengthValidationException from ValidateColumnLengths instead of ArgumentException,
// then catch only that here so internal ArgumentException subclasses (e.g. from Rfc2898DeriveBytes in the
// encryption path) still fall through to catch(Exception) for proper logging and 500 response.
catch (ColumnLengthValidationException ex)
{
    return BadRequest(new { error = ex.Message });
}
Prompt for LLM

File Web/Resgrid.Web.Services/Controllers/v4/ChatbotController.cs:

Line 305 to 309:

Overly broad exception handling in the `catch (ArgumentException ex)` block captures internal server errors from `_encryptionService.Encrypt()` where `Rfc2898DeriveBytes` throws `ArgumentNullException` for invalid encryption salts. Introduce a dedicated `ColumnLengthValidationException` thrown by `ValidateColumnLengths` and catch only that specific type to ensure genuine `ArgumentExceptions` fall through to `catch(Exception)`.

Suggested Code:

// Throw a dedicated ColumnLengthValidationException from ValidateColumnLengths instead of ArgumentException,
// then catch only that here so internal ArgumentException subclasses (e.g. from Rfc2898DeriveBytes in the
// encryption path) still fall through to catch(Exception) for proper logging and 500 response.
catch (ColumnLengthValidationException ex)
{
    return BadRequest(new { error = ex.Message });
}

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

/// <summary>
/// Validates that a string's UTF-8 encoded byte count does not exceed a maximum. Use when the
/// stored representation depends on byte length (e.g. values encrypted before persisting), where
/// a character-count check (StringLength) would pass multi-byte Unicode input that overflows a

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules low

Unsafe type casting violates team standards. Apply the as operator or pattern matching for all casts, ensuring proper null checks before usage.

Kody rule violation: Use safe type casting with as operator

Prompt for LLM

File Web/Resgrid.Web/Attributes/MaxUtf8BytesAttribute.cs:

Line 9:

Unsafe type casting violates team standards. Apply the `as` operator or pattern matching for all casts, ensuring proper null checks before usage.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

@ucswift

ucswift commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

Approve

@github-actions github-actions 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.

This PR is approved.

@ucswift
ucswift merged commit 7f7fb06 into master Aug 8, 2026
18 of 19 checks passed
This was referenced Aug 8, 2026
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