Skip to content

fix: avoid 500 errors when job parameters cannot be stored - #1007

Open
aldbr wants to merge 1 commit into
DIRACGrid:mainfrom
aldbr:fix-582-metadata-500
Open

fix: avoid 500 errors when job parameters cannot be stored#1007
aldbr wants to merge 1 commit into
DIRACGrid:mainfrom
aldbr:fix-582-metadata-500

Conversation

@aldbr

@aldbr aldbr commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #582

PATCH /api/jobs/metadata intermittently returns an unhandled 500:

opensearchpy.exceptions.RequestError: RequestError(400, 'x_content_parse_exception',
'[1:54] [UpdateRequest] failed to parse field [doc]')

Root cause: Python's JSON parser accepts the non-standard literals NaN and (-)Infinity, so such values survive request parsing. JobMetaData allows arbitrary extra fields with no value validation, so a non-finite float is forwarded verbatim to OpenSearch, whose strict JSON parser rejects the whole document and nothing logs the offending body.

This is caused by DIRAC#6938 where the Watchdog reports math.nan for LastUpdateCPU(s), DiskSpace(MB), MemoryUsed(MB) and LoadAverage for any job that ends before the first watchdog cycle (20–30 min), and these reach this endpoint through the legacy JobStateUpdateClient future client. A companion DIRAC PR stops sending them (link to be added).

This PR provides pydantic models with additional checks to reject non-finite numbers. Client gets a 422 status error instead of 500, naming the offending field.

Python's JSON parser accepts NaN and (-)Infinity so such values used to
survive request parsing and be forwarded to OpenSearch, which rejects
them with 'x_content_parse_exception ... failed to parse field [doc]',
resulting in an unhandled internal server error.

- Reject non-finite numbers in JobMetaData extra fields and
  HeartbeatData floats at the API boundary (HTTP 422)
- Sanitize non-finite numbers echoed back in validation error details
  so the 422 response itself can be serialized to JSON
- Wrap RequestError from BaseOSDB.upsert into a new DocumentUpsertError
  (HTTP 400) and log the offending document
- Re-raise DiracErrors from TaskGroups directly rather than wrapped in
  an ExceptionGroup so the FastAPI exception handlers can match them

Fixes DIRACGrid#582

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@read-the-docs-community

Copy link
Copy Markdown

Documentation build overview

📚 diracx | 🛠️ Build #33944219 | 📁 Comparing dccb2d6 against latest (503d3d2)

  🔍 Preview build  

1 file changed
± dev/reference/coding-conventions/index.html

return v

@model_validator(mode="after")
def validate_extra_fields_are_json_safe(self):

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.

Suggested change
def validate_extra_fields_are_json_safe(self):
def validate_extra_fields_are_json_safe(self) -> Self:

with from typing_extensions import Self

Comment on lines +100 to +102
for name, value in (self.model_extra or {}).items():
_ensure_finite_numbers(value, name)
return self

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.

Suggested change
for name, value in (self.model_extra or {}).items():
_ensure_finite_numbers(value, name)
return self
if self.model_extra:
for name, value in self.model_extra.items():
_ensure_finite_numbers(value, name)
return self

None, alias="BenchMark", description="Pilot benchmark value."
None,
alias="BenchMark",
allow_inf_nan=False,

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.

As I commented in the related DIRAC PR, I do not see how this can ever happen

RequestError, and the offending document must be logged.
"""
with pytest.raises(DocumentUpsertError, match="Failed to upsert document"):
await dummy_opensearch_db.upsert("dummyvo", 2, {"IntField": float("nan")})

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.

Test also against math.nan?

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.

Error 500: PATCH /api/jobs/metadata

2 participants