Skip to content

fix(clients): treat only GitLab JSON 404s as not found - #440

Merged
henrysachs merged 7 commits into
masterfrom
fix/notfound-require-json
Oct 20, 2026
Merged

henrysachs merged 7 commits into
masterfrom
fix/notfound-require-json

Conversation

@henrysachs

@henrysachs henrysachs commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Description of your changes

Why

IsResponseNotFound returned true for any 404. A proxy or ingress in front of GitLab also returns a 404 when its backend is down. The provider then called Create, which made duplicate resources, or it dropped the finalizer on Delete. GitLab renders API 404s as JSON, so this change treats a 404 as "not found" only when its media type is application/json.

What changed

  • IsResponseNotFound requires status 404 and media type application/json. It returns false for a nil res or a nil res.Response.
  • ldapgrouplinks Observe uses IsResponseNotFound instead of IsErrorLdapGroupLinkNotFound, which is removed. client-go v3 returns the same 404 Not Found error for every 404, so that string check matched proxy 404s too.
  • Existing 404 test fixtures now set Content-Type: application/json. New cases cover text/plain and text/html 404s.

Scope

  • Covers every IsResponseNotFound caller. A non-JSON 404 now returns an error, so the provider retries on the next reconcile.
  • Not in scope: the samlgrouplinks string check (Linked SAML group link not found) never matches the client-go v3 404 error. A SAML link deleted outside the provider stays in an error state and is not recreated. That bug already exists and is not caused by this change. Follow-up.

Merge order

Merge this PR late, after the open feature PRs (#430, #432–#437, #439, #442, #443) and before #441. Their new controller tests build 404 fixtures without Content-Type. With this change they would fail. Once those PRs are in master, this PR gets rebased and also sets Content-Type: application/json on their 404 fixtures, as it already does for the existing tests. A PR from that list that is not merged by then gets the header on its own branch instead.

Blast Radius

All controllers that detect "not found" with IsResponseNotFound. A real GitLab 404 behaves as before. A 404 from a proxy now shows Synced=False until GitLab comes back.

Verification

  • go test ./pkg/... ./apis/... and golangci-lint on the changed packages pass. The new tests fail on master and pass with the fix.
  • Live, real GitLab 19.4: I deleted a project Variable in GitLab. GitLab returned 404 application/json, and the provider recreated the variable within 5 s.
  • Live, local proxy that returns a text/plain 404 for GETs and forwards POSTs: on master the Badge MR got a second badge (ids 1 and 2) and its external-name moved to 2. With the fix, the proxy logged 0 POSTs, the MR showed observe failed: cannot get Gitlab badge: 404 Not Found, and GitLab kept one badge.

Fixes #425

I have:

  • Read and followed Crossplane's contribution process.
  • Run make reviewable test to ensure this PR is ready for review.

How has this code been tested

See Verification.

Signed-off-by: Henry Sachs <henry.sachs@deutschebahn.com>
Signed-off-by: Henry Sachs <henry.sachs@deutschebahn.com>
Signed-off-by: Henry Sachs <henry.sachs@deutschebahn.com>
Signed-off-by: Henry Sachs <henry.sachs@deutschebahn.com>
…bserve

approvalrules ErrGet404 had no external name, so Observe returned before calling GitLab. project serviceaccounts had no 404 case.

Signed-off-by: Henry Sachs <henry.sachs@deutschebahn.com>

@BoxBoxJason BoxBoxJason 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.

Great fix !

That's the exact solution I was envisionning !

I check against a live gitlab instance (non paid plan). All of the endpoints do return a json type error, so no worries, this is not a breaking change

IsResponseNotFound now requires a JSON 404. Update the fixtures of controllers merged after this branch was cut.

Signed-off-by: Henry Sachs <henry.sachs@deutschebahn.com>
@henrysachs
henrysachs merged commit a6a16a5 into master Oct 20, 2026
9 checks passed
henrysachs added a commit that referenced this pull request Oct 20, 2026
IsResponseNotFound now requires a JSON Content-Type (#440).

Signed-off-by: Henry Sachs <henry.sachs@deutschebahn.com>
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.

Non-GitLab 404s (proxy/ingress) are treated as "resource deleted", causing duplicate resources

3 participants