Skip to content

fix: avoid warning spam when default spinner SVG is missing#40481

Open
durgaprasadml wants to merge 3 commits into
apache:masterfrom
durgaprasadml:fix-spinner-warning-40478
Open

fix: avoid warning spam when default spinner SVG is missing#40481
durgaprasadml wants to merge 3 commits into
apache:masterfrom
durgaprasadml:fix-spinner-warning-40478

Conversation

@durgaprasadml
Copy link
Copy Markdown

Summary

Avoid warning log pollution when the default spinner SVG asset is unavailable in packaged/runtime environments.

In production deployments, frontend source assets under superset-frontend/ are not packaged or shipped. The backend fallback helper get_default_spinner_svg() attempted to load the frontend source SVG directly, causing repeated warning logs when the file was missing:

text id="fwbmtx" Could not load default spinner SVG: [Errno 2] No such file or directory ...

Since the spinner asset is optional and frontend production builds already package spinner assets separately, the warning was unnecessary and polluted logs in containerized/runtime deployments.

This change:

  • checks whether the SVG file exists before attempting to read it
  • silently returns None when the file is absent
  • continues logging warnings for unexpected read failures such as OSError or UnicodeDecodeError

Files Changed

  • superset/views/base.py
  • tests/unit_tests/views/test_base_theme_helpers.py

Tests Added

Added regression coverage for:

  • missing SVG file returns None without warning logs
  • unexpected read failures log warnings and return None
  • successful SVG reads return SVG contents correctly

Validation

Executed:

bash id="9szt7w" PYTHONPATH=. pytest tests/unit_tests/views/test_base_theme_helpers.py

Result:

text id="mzgw0c" 34 passed

Also executed:

bash id="e98wjv" pre-commit run --files superset/views/base.py tests/unit_tests/views/test_base_theme_helpers.py

All checks passed.

Edge Cases Considered

  • race conditions between existence check and file open
  • custom spinner overrides via brandSpinnerSvg / brandSpinnerUrl
  • production/container runtime environments without frontend source assets

Fixes #40478

@dosubot dosubot Bot added the change:backend Requires changing the backend label May 28, 2026
@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented May 28, 2026

Code Review Agent Run #bf6d83

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: ba6eaaf..ba6eaaf
    • superset/views/base.py
    • tests/unit_tests/views/test_base_theme_helpers.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Comment thread superset/views/base.py Outdated
Comment on lines +431 to +432
if not os.path.exists(svg_path):
return None
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.

Suggestion: The existence pre-check can silently swallow filesystem access problems and skip the warning path you intended to keep for unexpected read failures. os.path.exists() returns False when stat() fails (for example due to permission-denied on parent directories), so the function returns None as if the file were missing instead of logging the underlying error. Handle missing-file behavior in the open() exception flow (suppress only file-not-found) so non-missing I/O failures are still reported. [incorrect condition logic]

Severity Level: Major ⚠️
- ⚠️ SPA endpoints hide spinner filesystem permission misconfigurations.
- ⚠️ Harder to diagnose asset permission issues from logs.
Steps of Reproduction ✅
1. In a running Superset deployment, ensure the default spinner is using the backend
helper by not setting `brandSpinnerSvg` or `brandSpinnerUrl` in the theme tokens used by
`get_spa_template_context` in `superset/views/base.py:580-641`, so the code at
`superset/views/base.py:63-70` (file lines 620-627 from the Read output) follows the `elif
not theme_tokens.get("brandSpinnerUrl"):` branch and calls `get_default_spinner_svg()`.

2. On the filesystem, create the SVG file at the path constructed in
`get_default_spinner_svg()` (`superset/views/base.py:37-49` in the snippet, corresponding
to diff lines 416-428) but remove execute/read permission from one of its parent
directories (for example `superset-frontend/`), so that `os.stat(svg_path)` fails with a
`PermissionError` even though the file exists; per CPython semantics,
`os.path.exists(svg_path)` in `superset/views/base.py:431` will return `False` when this
`stat()` call fails.

3. Trigger any SPA view that uses `render_app_template()`, for example send an
authenticated `GET /extensions/list/` request, which is handled by `ExtensionsView.list()`
in `superset/extensions/view.py:7-11`, calling `super().render_app_template()`, which in
turn calls `get_spa_template_context()` in `superset/views/base.py:240-243` and ultimately
`get_default_spinner_svg()` at `superset/views/base.py:409-60`.

4. Observe that `get_default_spinner_svg()` returns `None` early via the `if not
os.path.exists(svg_path): return None` branch at `superset/views/base.py:431-432`, so the
`try/except (OSError, UnicodeDecodeError)` block at `superset/views/base.py:435-60` is
never entered and no `logger.warning("Could not load default spinner SVG: %s", e)` message
is emitted, even though the underlying filesystem error is a permission problem rather
than a genuinely missing file; if the pre-check were removed and missing-file handling
moved into the `open()` exception flow (catching `FileNotFoundError` separately), the same
misconfiguration would result in a warning log as originally intended for unexpected I/O
failures.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset/views/base.py
**Line:** 431:432
**Comment:**
	*Incorrect Condition Logic: The existence pre-check can silently swallow filesystem access problems and skip the warning path you intended to keep for unexpected read failures. `os.path.exists()` returns `False` when `stat()` fails (for example due to permission-denied on parent directories), so the function returns `None` as if the file were missing instead of logging the underlying error. Handle missing-file behavior in the `open()` exception flow (suppress only file-not-found) so non-missing I/O failures are still reported.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@bito-code-review
Copy link
Copy Markdown
Contributor

The suggestion is valid and addresses a real issue in the code. The current implementation uses os.path.exists() to check for the existence of a file before attempting to open it. However, this approach can silently swallow filesystem access problems, such as permission issues on parent directories, leading to incorrect behavior where the function returns None as if the file were missing, instead of logging the underlying error.

The suggested fix is to move the missing-file check into the open() exception flow, catching only FileNotFoundError and allowing other I/O errors to be reported. This ensures that permission issues and other unexpected I/O failures are logged as intended.

To implement this fix, you can modify the code to remove the os.path.exists() check and handle the missing-file case within the try/except block. Here's a concise implementation of the fix:

superset/views/base.py

def get_default_spinner_svg():
    svg_path = ...  # logic to construct the path
    try:
        with open(svg_path, 'r') as f:
            return f.read()
    except FileNotFoundError:
        # Handle missing file case
        return None
    except (OSError, UnicodeDecodeError) as e:
        logger.warning("Could not load default spinner SVG: %s", e)
        return None

@sfirke
Copy link
Copy Markdown
Member

sfirke commented May 28, 2026

Hi @durgaprasadml ! Thanks for the fix. Please see the comments left by both bots.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 28, 2026

Codecov Report

❌ Patch coverage is 75.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 55.86%. Comparing base (9441240) to head (bb12f22).
⚠️ Report is 24 commits behind head on master.

Files with missing lines Patch % Lines
superset/views/base.py 75.00% 1 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (9441240) and HEAD (bb12f22). Click for more details.

HEAD has 50 uploads less than BASE
Flag BASE (9441240) HEAD (bb12f22)
python 40 5
presto 4 1
hive 4 1
unit 12 3
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #40481      +/-   ##
==========================================
- Coverage   64.17%   55.86%   -8.32%     
==========================================
  Files        2592     2593       +1     
  Lines      139299   139677     +378     
  Branches    32347    32439      +92     
==========================================
- Hits        89395    78025   -11370     
- Misses      48367    60985   +12618     
+ Partials     1537      667     -870     
Flag Coverage Δ
hive 39.08% <75.00%> (-0.13%) ⬇️
mysql ?
postgres ?
presto 40.75% <75.00%> (-0.14%) ⬇️
python 42.13% <75.00%> (-18.21%) ⬇️
sqlite ?
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@durgaprasadml
Copy link
Copy Markdown
Author

Thanks for the review and for pointing out the issue with the os.path.exists() pre-check.

I updated the implementation to follow the suggested EAFP-style handling by:

  • removing the explicit existence check
  • handling FileNotFoundError silently
  • continuing to log unexpected OSError / UnicodeDecodeError cases

All checks are now passing successfully.

Comment thread superset/views/base.py
@pull-request-size pull-request-size Bot added size/L and removed size/M labels May 29, 2026
@durgaprasadml durgaprasadml requested a review from semohr May 29, 2026 18:12
@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented May 29, 2026

Code Review Agent Run #d27019

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: ba6eaaf..bb12f22
    • superset/views/base.py
    • tests/unit_tests/views/test_base_theme_helpers.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@durgaprasadml
Copy link
Copy Markdown
Author

@semohr review

@semohr
Copy link
Copy Markdown
Contributor

semohr commented May 30, 2026

I have no say here and am not a maintainer. Just came here because I had the same issue.

From my perspective this seems good 🤷‍♀️

@durgaprasadml
Copy link
Copy Markdown
Author

@sfirke review

@sfirke
Copy link
Copy Markdown
Member

sfirke commented May 30, 2026

@semohr I appreciate your input! You pushed this to be a better fix, doesn't matter if you're a committer. Thank you!

I will review on Monday when I'm back at work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:backend Requires changing the backend size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Could not load default spinner" error pollutes Superset 6.1.0 logs

3 participants