aosabook/500lines · error · ServerException

'{0}' not found

Error message

'{0}' not found

What it means

Thrown by case_no_file.act in a teaching web server (the 500 Lines 'A Python Web Server' chapter). The request handler first translates the URL into handler.full_path; case_no_file.test returns True when os.path.exists(handler.full_path) is False, and act raises ServerException with the requested path. The handler's outer try/except catches ServerException and renders a 404 page, so this is the server's canonical 'file or directory does not exist' signal.

Source

Thrown at web-server/code/05-refactored/server.py:41

    def index_path(self, handler):
        return os.path.join(handler.full_path, 'index.html')

    def test(self, handler):
        assert False, 'Not implemented.'

    def act(self, handler):
        assert False, 'Not implemented.'

#-------------------------------------------------------------------------------

class case_no_file(base_case):
    '''File or directory does not exist.'''

    def test(self, handler):
        return not os.path.exists(handler.full_path)

    def act(self, handler):
        raise ServerException("'{0}' not found".format(handler.path))

#-------------------------------------------------------------------------------

class case_cgi_file(base_case):
    '''Something runnable.'''

    def run_cgi(self, handler):
        cmd = "python " + handler.full_path
        child_stdin, child_stdout = os.popen2(cmd)
        child_stdin.close()
        data = child_stdout.read()
        child_stdout.close()
        handler.send_content(data)

    def test(self, handler):
        return os.path.isfile(handler.full_path) and \
               handler.full_path.endswith('.py')

View on GitHub (pinned to fba689d101)

Solutions

  1. Verify the resource exists under the configured root: os.path.exists on the exact handler.full_path value.
  2. Check the URL->path translation (the root join) for off-by-one slashes or a missing Root dereference.
  3. Correct the URL casing/typo to match the on-disk filename.
  4. Restore or recreate the missing file/directory, or register it with the server.
  5. If the path legitimately may be absent, add a case before case_no_file to serve a configured fallback.

Example fix

// before: requesting a missing resource
GET /inde.html HTTP/1.1   ->  raises ServerException("'/inde.html' not found")

// after: validate the path translation before the case loop
full_path = os.path.join(Root, handler.path.lstrip('/'))
if not os.path.exists(full_path):
    # log the resolved path, fix Root or the URL, then retry
Defensive patterns

Strategy: validation

Validate before calling

# before issuing/extending a case, confirm the path exists
import os
full_path = os.path.join(ROOT_DIR, path.lstrip('/'))
if not os.path.exists(full_path):
    # log and return a 404 rather than letting ServerException propagate
    return False

Try / catch

# if you extend the handler, catch the server's own exception type
try:
    handler.handle_request()
except ServerException as e:
    log.warning('request failed: %s', e)

Prevention

When it happens

Trigger: Any GET/HEAD request whose resolved filesystem path does not exist: a typo'd URL, a deleted file, a missing directory, or a path whose case does not match the on-disk filename. It fires only after os.path.exists(handler.full_path) returns False, i.e. before any file/directory/CGI case is evaluated.

Common situations: Wrong document root configured so full_path points outside the intended tree; URL->path join that mishandles a leading/trailing slash; files renamed or moved after deployment; case-sensitivity mismatch when deploying from macOS/Windows to Linux; a symlink whose target was removed.


AI-assisted analysis of aosabook/500lines@fba689d101 (2026-08-13). Data as JSON: /api/errors/f9b81ae97b1362b1. Report an issue: GitHub.