From 998944134a069f7f23cf2397bcd6f0daaef176f8 Mon Sep 17 00:00:00 2001 From: Tom Elliott Date: Sat, 29 Aug 2026 13:37:38 -0500 Subject: [PATCH 1/2] A refused delete now shows a sentence, not the SQL The page described what a refused delete looked like when the raw MariaDB constraint violation was what reached the screen. FOG now translates it: Cannot delete this storage group because a location still refers to it. Reassign or remove it first. The database's own text is still possible -- a constraint added by hand, or left by an older release, has no plain-English description to look up -- so it is kept as a note with the guidance on reading it, rather than dropped. That is the accurate relationship between the two: one is what you normally see, the other is the fallback. Added the API side, which the page did not cover at all: the same message comes back as HTTP 409 Conflict with the sentence in `msg`. Worth stating because 409 specifically means the request was fine and will work once the blocking record is dealt with, which is what lets a script tell "fix this and retry" apart from "this request was wrong". Co-Authored-By: Claude --- docs/kb/reference/referential-integrity.md | 39 ++++++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/docs/kb/reference/referential-integrity.md b/docs/kb/reference/referential-integrity.md index 465e569..e8f5807 100644 --- a/docs/kb/reference/referential-integrity.md +++ b/docs/kb/reference/referential-integrity.md @@ -121,22 +121,39 @@ the next user created could inherit someone else's sign-in binding. ## What a refused delete looks like -The refusal comes from the database, and FOG surfaces the database's own -message. It names the constraint, and the constraint is named after the table -and column that is still pointing at the record: +The refusal comes from the database, but what you see is a sentence naming +what is still using the record: ``` -Cannot delete or update a parent row: a foreign key constraint fails -(`fog`.`nfsGroupMembers`, CONSTRAINT `fk_nfsGroupMembers_ngmGroupID` -FOREIGN KEY (`ngmGroupID`) REFERENCES `nfsGroups` (`ngID`)) +Cannot delete this storage group because a location still refers to it. +Reassign or remove it first. ``` -Read it as: **`nfsGroupMembers` still has rows in this group** — a storage -node has not been moved out. `fk__` always identifies what is -holding the record. +Move or delete the thing it names, then try the delete again. **Nothing was +changed** — a refused delete leaves the record and everything pointing at it +exactly as they were. -Nothing was changed when a delete is refused. Clear the thing named in the -message and try again. +Over the API the same message comes back as **HTTP 409 Conflict**, with the +sentence in the `msg` field. 409 rather than a generic error is deliberate: +it means the request itself was fine and will work once the blocking record +is dealt with, so a script can tell "fix this and retry" apart from "this +request was wrong". + +>[!note] +>Occasionally the message is the database's own instead: +> +>``` +>Cannot delete or update a parent row: a foreign key constraint fails +>(`fog`.`nfsGroupMembers`, CONSTRAINT `fk_nfsGroupMembers_ngmGroupID` +>FOREIGN KEY (`ngmGroupID`) REFERENCES `nfsGroups` (`ngID`)) +>``` +> +>That happens when the rule involved is one FOG does not have a plain-English +>description for — a constraint added by hand, or left by an older release. +>The delete is still refused and nothing is changed; only the wording is +>less helpful. Read it as **`nfsGroupMembers` still has rows in this group**: +>the constraint name is always `fk_
_`, and that table and +>column are what is holding the record. ## What happens on upgrade From 554a821065211692b7815d3e534b6b3fb1b9b6ac Mon Sep 17 00:00:00 2001 From: Tom Elliott Date: Sat, 29 Aug 2026 13:42:05 -0500 Subject: [PATCH 2/2] Correct where the API returns the message Said the sentence arrives in a `msg` field. It does not -- the router echoes the message as the response body, so that is what a script reads. Co-Authored-By: Claude --- docs/kb/reference/referential-integrity.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/kb/reference/referential-integrity.md b/docs/kb/reference/referential-integrity.md index e8f5807..0357ba4 100644 --- a/docs/kb/reference/referential-integrity.md +++ b/docs/kb/reference/referential-integrity.md @@ -134,10 +134,10 @@ changed** — a refused delete leaves the record and everything pointing at it exactly as they were. Over the API the same message comes back as **HTTP 409 Conflict**, with the -sentence in the `msg` field. 409 rather than a generic error is deliberate: -it means the request itself was fine and will work once the blocking record -is dealt with, so a script can tell "fix this and retry" apart from "this -request was wrong". +sentence as the response body. 409 rather than a generic error is +deliberate: it means the request itself was fine and will work once the +blocking record is dealt with, so a script can tell "fix this and retry" +apart from "this request was wrong". >[!note] >Occasionally the message is the database's own instead: