fix(): S3 compat for on-prem (s3proxy/MinIO) and graceful empty-log handling#1893
fix(): S3 compat for on-prem (s3proxy/MinIO) and graceful empty-log handling#1893benflexcompute merged 5 commits intomainfrom
Conversation
…andling Two fixes for Nexus (on-premises) deployments: 1. S3 checksum compatibility: newer boto3 versions send x-amz-checksum headers by default, which s3proxy and some MinIO versions do not implement — causing PutObject to fail with NotImplemented. When s3_endpoint_url is set (indicating a non-AWS S3 backend), disable default checksum calculation/validation via BotocoreConfig. This is a no-op for production (AWS S3) since the setting only activates when a custom endpoint is configured. 2. Log access on errored jobs: accessing case.logs.tail() on a job that never produced solver logs (e.g. meshing failed before solver ran) threw an IndexError from an unchecked [0] on an empty list. Now raises FileNotFoundError with a clear message instead. Made-with: Cursor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
There was a problem hiding this comment.
Pull request overview
This PR improves the Flow360 Python client’s robustness in two areas that commonly affect on-prem/Nexus dev setups: S3-compatible storage uploads (e.g., s3proxy/MinIO) and handling resources that never produced solver logs.
Changes:
- Adjust S3 client construction to disable default checksum header behavior when using a custom
s3_endpoint_url(S3-compatible backends). - Make
RemoteResourceLogsraise a clearFileNotFoundErrorwhen no log files exist instead of failing with anIndexError.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
flow360/component/resource_base.py |
Adds explicit empty-log detection and raises FileNotFoundError with a clearer message. |
flow360/cloud/s3_utils.py |
Extends botocore client config for custom S3 endpoints to avoid incompatible checksum headers/validation. |
Comments suppressed due to low confidence (1)
flow360/cloud/s3_utils.py:169
- There’s now behavior branching on
Env.current.s3_endpoint_urlto change checksum settings, but there are existing tests forflow360/cloud/s3_utils.py(e.g.tests/test_s3_utils.py) and none validate thatget_client()passes the intendedBotocoreConfigwhen a custom endpoint is set. Adding a unit test that monkeypatchesboto3.clientto capture theconfigargument would help prevent regressions in the on-prem compatibility fix.
config_kwargs = {"max_pool_connections": MAX_POOL}
if Env.current.s3_endpoint_url is not None:
# S3-compatible stores (s3proxy, MinIO) may not implement the
# checksum headers that newer boto3 versions send by default.
config_kwargs["request_checksum_calculation"] = "when_required"
config_kwargs["response_checksum_validation"] = "when_required"
kwargs = {
"region_name": self.user_credential.region,
"aws_access_key_id": self.user_credential.access_key_id,
"aws_secret_access_key": self.user_credential.secret_access_key,
"aws_session_token": self.user_credential.session_token,
"config": BotocoreConfig(**config_kwargs),
}
if Env.current.s3_endpoint_url is not None:
kwargs["endpoint_url"] = Env.current.s3_endpoint_url
return client("s3", **kwargs)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Change FileNotFoundError → Flow360RuntimeError so the exception is not silently caught by the except OSError handlers in _get_log_by_pos and _get_log_by_level (FileNotFoundError is a subclass of OSError) - Move log file check before TemporaryLogDirectory creation to avoid leaving an unused temp dir when no logs exist - Wrap BotocoreConfig construction in try/except TypeError to gracefully fall back when older botocore versions don't support the checksum config options - Add two tests for the empty-log scenario: empty file list and file list with no matching *.log entries Made-with: Cursor
Made-with: Cursor
Virtual-hosted style (http://bucket.host/key) requires DNS resolution of the bucket subdomain, which fails in Kubernetes and single-node on-prem setups. Path-style (http://host/bucket/key) works universally with s3proxy, MinIO, and real AWS S3. Only activated when s3_endpoint_url is set (on-prem); production behavior unchanged. Made-with: Cursor
mikeparkflex
left a comment
There was a problem hiding this comment.
My agent with context from debugging concurs. No open items remaining. Both PRs are ready to merge.

Summary
s3_endpoint_urlis set (Nexus/on-prem deployments), disable default boto3 checksum headers (x-amz-checksum-*) viaBotocoreConfig(request_checksum_calculation="when_required"). s3proxy does not implement these headers, causingPutObjectto fail withNotImplemented. This is a no-op for production (AWS S3) since the setting only activates when a custom endpoint is configured.case.logs.tail()on a job that never produced solver logs (e.g. meshing failed before solver ran) threwIndexErrorfrom an unchecked[0]on an empty list. Now raisesFileNotFoundErrorwith a clear message.Context
Discovered during Nexus dev setup testing with the flow360 Python client. The S3 issue affects all file uploads when using s3proxy (Nexus dev) or certain MinIO versions (Nexus release packages). The log fix is a minor edge case for errored jobs.
Test plan
case._download_file()still works for file downloadscase.logs.tail()now givesFileNotFoundErrorinstead ofIndexErrorwhen no logs exists3_endpoint_urlisNone)Made with Cursor
Note
Medium Risk
Changes S3 client configuration (checksums and addressing style) when using a custom endpoint, which could affect upload/download behavior in on-prem deployments. Also changes log retrieval to raise a clearer runtime error when no log files exist, altering error behavior for some failed jobs.
Overview
Improves S3 compatibility for on-prem/S3-compatible backends by customizing
BotocoreConfigwhenEnv.current.s3_endpoint_urlis set: disables default checksum headers, forces path-style addressing, and falls back gracefully on olderbotocoreversions.Updates
RemoteResourceLogs._get_tmp_file_name()to detect when no.logfiles are available and raiseFlow360RuntimeErrorwith a clear message instead of failing via list indexing; adds tests covering empty and non-matching file lists.Written by Cursor Bugbot for commit c5852ee. This will update automatically on new commits. Configure here.