MemberJunction / MemberJunction/MJ

BaseEntity.Validate() accepts an empty string for a NOT NULL string column, so a required field the form paints red still saves

Open Beginner friendly
#4,359 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TSQL
Stars
29
Forks
6
Avg merge
2d 1h
Merged PRs (30d)
323

Description

## Summary

`EntityField.Validate()` treats an empty string as satisfying a NOT NULL string column, so a required field that the form paints red as "required and empty" still saves — with `''` persisted in the column. The UI and the save disagree about the same value.

## Repro

MJ `next` @ `6ac6bcc5ca` (6.1.0-edge), Explorer, any entity with a NOT NULL nvarchar column that has no default. Used `MJ: AI Agent Request Types` → `Name` (nvarchar(200), `AllowsNull = 0`, no default).

1. Open an existing record, click **Edit**.
2. Clear `Name`. The field paints its underline red (`mj-forms-field--required-empty`) — the form clearly considers it invalid.
3. Click **Save**.

**Expected:** the save is refused with a field-named validation failure, the same way a `null` would be.
**Actual:** "Record saved successfully". The row now has `Name = ''` (`LEN(Name) = 0`, verified in SQL). Observed live on 2026-09-10 while validating #4355; the record was restored by hand.

## Root cause

`packages/MJCore/src/generic/baseEntity.ts`, `EntityField.Validate()`, nullability rung:

```ts
if (!ef.AllowsNull && (this.Value === null || this.Value === undefined)) {
```

Only `null` / `undefined` fail. `''` passes, and SQL Server accepts `''` in a NOT NULL column, so nothing downstream catches it either.

The form field takes the opposite view — `MjFormFieldComponent.IsRequiredEmpty`:

```ts
return val === null || val === undefined || val === '';
```

So the two rules that are supposed to describe the same thing ("this required field has no value") disagree exactly on `''`. The new section indicators from #4355 mirror the field rule, so they also flag `''` as invalid before save — consistent with the field, inconsistent with `Validate()` until this is settled.

## Proposed fix

Treat an empty (or whitespace-only) string as "missing" for `AllowsNull === false` **string** columns in `EntityField.Validate()`:

```ts
const missing = this.Value === null || this.Value === undefined
|| (ef.TSType === EntityFieldTSType.String && typeof this.Value === 'string' && this.Value.trim().length === 0);
if (!ef.AllowsNull && missing) { ... }
```

keeping the existing default-value / new-record carve-out as is. That matches what a user means by a required text field, and it is what the form already promises visually.

If there are entities where an empty string in a NOT NULL column is legitimately meaningful, the alternative is the other direction — stop `IsRequiredEmpty` from painting `''` red — but that seems the less useful contract. Either way the two should agree.

## Notes

- Not a regression: the nullability rung has read this way for a long time; #4355 just made the disagreement visible at the section level as well as the field level.
- Test to add alongside the fix: `packages/MJCore/src/__tests__/` — a NOT NULL string field set to `''` and to `' '` on an existing record fails `Validate()` with `Source` = the field name; a nullable string field set to `''` still passes.

Contributor guide

Open the contributing guide

Research direction

Start in packages/MJCore/src/generic/baseEntity.ts at EntityField.Validate(), then inspect MjFormFieldComponent.IsRequiredEmpty to compare the existing required-field rules. Add tests under packages/MJCore/src/__tests__/ for empty and whitespace-only values on non-null string fields, while confirming nullable empty strings still pass. Done means validation reports the field name and blocks the save consistently with the form.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.