Skip to content

Show invalid IP errors in network explorer search#3534

Merged
johannaengland merged 1 commit into5.14.xfrom
bugfix/networkexplorer-search-errors
Sep 18, 2025
Merged

Show invalid IP errors in network explorer search#3534
johannaengland merged 1 commit into5.14.xfrom
bugfix/networkexplorer-search-errors

Conversation

@johannaengland
Copy link
Copy Markdown
Contributor

@johannaengland johannaengland commented Sep 11, 2025

Scope and purpose

When reviewing #3529 I noticed that the bug that @Simrayz found goes actually even deeper than the frontend just showing when a search failed.

Because every time an invalid IP was given and exact search chosen that triggered an internal server error:

[Thu Sep 11 12:30:53 2025] [ERROR] [pid=56276 django.request] Internal Server Error: /networkexplorer/search/
Traceback (most recent call last):
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/views/generic/base.py", line 105, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/views/generic/base.py", line 144, in dispatch
    return handler(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/nav/python/nav/web/networkexplorer/views.py", line 106, in get
    context = self.form_valid(form)
              ^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/nav/python/nav/web/networkexplorer/views.py", line 100, in form_valid
    return search(form.cleaned_data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/nav/python/nav/web/networkexplorer/search.py", line 52, in search
    ) = search_function(query, exact_results)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/nav/python/nav/web/networkexplorer/search.py", line 258, in ip_search
    gwportprefixes = GwPortPrefix.objects.filter(gw_ip=ip)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/query.py", line 1436, in filter
    return self._filter_or_exclude(False, args, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/query.py", line 1454, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/query.py", line 1461, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/sql/query.py", line 1546, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/sql/query.py", line 1577, in _add_q
    child_clause, needed_inner = self.build_filter(
                                 ^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/sql/query.py", line 1492, in build_filter
    condition = self.build_lookup(lookups, col, value)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/sql/query.py", line 1319, in build_lookup
    lookup = lookup_class(lhs, rhs)
             ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/lookups.py", line 27, in __init__
    self.rhs = self.get_prep_lookup()
               ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/lookups.py", line 341, in get_prep_lookup
    return super().get_prep_lookup()
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/lookups.py", line 85, in get_prep_lookup
    return self.lhs.output_field.get_prep_value(self.rhs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/vscode/.venv/lib/python3.11/site-packages/django/db/models/fields/__init__.py", line 2423, in get_prep_value
    return self.to_python(value)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/nav/python/nav/models/fields.py", line 110, in to_python
    raise exceptions.ValidationError("Value must be a valid CIDR address")
django.core.exceptions.ValidationError: ['Value must be a valid CIDR address']
[11/Sep/2025 12:30:53] "GET /networkexplorer/search/?query_0=invalid&query_1=ip&exact_results=on HTTP/1.1" 500 163796

To reproduce:
Go to /networkexplorer/, enter invalid into the search field and select IP in the dropdown, select "Search exact (no substring)", the click "Search". See internal server error.

The only thing this PR is lacking is a way for the frontend to show the errors that are being send in as context. Maybe @Simrayz can help me there?

Contributor Checklist

Every pull request should have this checklist filled out, no matter how small it is.
More information about contributing to NAV can be found in the
Hacker's guide to NAV.

  • Added a changelog fragment for towncrier
  • Added/amended tests for new/changed code
  • Added/changed documentation
  • Linted/formatted the code with ruff, easiest by using pre-commit
  • The first line of the commit message continues the sentence "If applied, this commit will ...", starts with a capital letter, does not end with punctuation and is 50 characters or less long. See https://cbea.ms/git-commit/
  • This pull request is based on the correct upstream branch: For a patch/bugfix affecting the latest stable version, it should be based on that version's branch (<major>.<minor>.x). For a new feature or other additions, it should be based on master.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Sep 11, 2025

Test results

   12 files     12 suites   12m 8s ⏱️
2 377 tests 2 377 ✅ 0 💤 0 ❌
6 666 runs  6 666 ✅ 0 💤 0 ❌

Results for commit e5f2160.

♻️ This comment has been updated with latest results.

@codecov
Copy link
Copy Markdown

codecov bot commented Sep 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.29%. Comparing base (1bef8d1) to head (e5f2160).
⚠️ Report is 15 commits behind head on 5.14.x.

Additional details and impacted files
@@           Coverage Diff           @@
##           5.14.x    #3534   +/-   ##
=======================================
  Coverage   61.28%   61.29%           
=======================================
  Files         610      610           
  Lines       44713    44724   +11     
  Branches       43       43           
=======================================
+ Hits        27401    27412   +11     
  Misses      17302    17302           
  Partials       10       10           

☔ 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.

@johannaengland johannaengland force-pushed the bugfix/networkexplorer-search-errors branch from 024ace1 to 4000480 Compare September 11, 2025 11:32
Copy link
Copy Markdown
Contributor

@Simrayz Simrayz Sep 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order for the AJAX call on the frontend to know that an error happened, the view has to return an error HTTP status code, e.g.

    def get(self, request, *_args, **_kwargs):
        form = NetworkSearchForm(request.GET)
        status = 200

        if form.is_valid():
            context = self.form_valid(form)
        else:
            context = self.form_invalid(form)
            status = 400

        return self.render_json_response(context, status=status)

This will trigger the .fail(...) handler in the submitForm function

.fail(function () { notifyFail('Search failed!'); })

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.

Right now it shows "Search failed!" regardless of the error, but we could check for errors in the response, and then display a concatenated error instead of the fallback "Search failed!"

            .fail(function (response) {
                const errors = response?.responseJSON?.errors;
                if (!errors) {
                    return notifyFail('Search failed!');
                }
                const errorMsg = Object.values(errors)
                    .flat()
                    .join(', ');
                notifyFail(errorMsg);
            })

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now it shows "Search failed!" regardless of the error, but we could check for errors in the response, and then display a concatenated error instead of the fallback "Search failed!"

Yes, I think that would be great!

Copy link
Copy Markdown
Contributor

@Simrayz Simrayz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the branch pointing to 5.14.x and not master?

The code returns the error in the response, but the client JS can't react to an error without using an error http status code, e.g. 400 for Bad Request

In addition, the errors won't show up due to this if block:

{% if errors %}
<div class="row">
<div id="notify_area" class="large-12 columns">
</div>
</div>
{% endif %}

The only "bug fix" I did #3529 was to always render the if block contents, so the request.fail handler has somewhere to show the error in the dom :)

@johannaengland
Copy link
Copy Markdown
Contributor Author

Why is the branch pointing to 5.14.x and not master?

Because this is a bugfix to code that has not been change since the latest stable release, see the PR template ("For a patch/bugfix affecting the latest stable version, it should be based on that version's branch (..x). For a new feature or other additions, it should be based on master.")

@johannaengland johannaengland requested review from a team and Simrayz September 16, 2025 13:18
Copy link
Copy Markdown
Contributor

@Simrayz Simrayz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great :) I can add the frontend changes if you want.

@johannaengland
Copy link
Copy Markdown
Contributor Author

I can add the frontend changes if you want.

That would be great! I think it would be easiest to make a new pull request and have that with master as its target branch, since you added other frontend changes in #3529

@johannaengland johannaengland force-pushed the bugfix/networkexplorer-search-errors branch from d32d0bb to e5f2160 Compare September 18, 2025 06:02
@sonarqubecloud
Copy link
Copy Markdown

@johannaengland johannaengland merged commit f37e6ce into 5.14.x Sep 18, 2025
17 checks passed
@johannaengland johannaengland deleted the bugfix/networkexplorer-search-errors branch September 18, 2025 06:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants