{"record":{"id":"743f9530708d113f","repo":"HumanSignal/label-studio","slug":"directory-indexes-are-not-allowed-here","errorCode":null,"errorMessage":"Directory indexes are not allowed here.","messagePattern":"Directory indexes are not allowed here\\.","errorType":"http","errorClass":"Http404","httpStatus":404,"severity":"error","filePath":"label_studio/core/utils/static_serve.py","lineNumber":61,"sourceCode":"    also set ``show_indexes`` to ``True`` if you'd like to serve a basic index\n    of the directory.  This index view will use the template hardcoded below,\n    but if you'd like to override it, you can create a template called\n    ``static/directory_index.html``.\n\n    If manifest_asset_prefix is provided, we will try to serve the file from the manifest.json\n    if the file is not found in the document_root.\n\n    Example:\n        path = \"main.js\"\n        document_root = \"/dist/apps/labelstudio/\"\n        manifest_asset_prefix = \"react-app\"\n        manifest_json = {\"main.js\": \"/react-app/main.123456.js\"}\n        fullpath = Path(safe_join(document_root, \"main.123456.js\"))\n    \"\"\"\n    path = posixpath.normpath(path).lstrip('/')\n    fullpath = Path(safe_join(document_root, path))\n    if fullpath.is_dir():\n        raise Http404(_('Directory indexes are not allowed here.'))\n    if manifest_asset_prefix and not fullpath.exists():\n        possible_asset = get_manifest_asset(path)\n        manifest_asset_prefix = (\n            f'/{manifest_asset_prefix}' if not manifest_asset_prefix.startswith('/') else manifest_asset_prefix\n        )\n        if possible_asset.startswith(manifest_asset_prefix):\n            possible_asset = possible_asset[len(manifest_asset_prefix) :]\n        fullpath = Path(safe_join(document_root, possible_asset))\n    if not fullpath.exists():\n        raise Http404(_('“%(path)s” does not exist') % {'path': fullpath})\n    # Respect the If-Modified-Since header.\n    statobj = fullpath.stat()\n    if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'), statobj.st_mtime):\n        return HttpResponseNotModified()\n    content_type, encoding = static_file_content_type_and_encoding(str(fullpath))\n\n    response = RangedFileResponse(request, fullpath.open('rb'), content_type=content_type)\n    response['Last-Modified'] = http_date(statobj.st_mtime)","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/core/utils/static_serve.py#L43-L79","documentation":"The static file serving view (serve in static_serve.py) resolves the requested path under document_root via safe_join; if the resolved fullpath is a directory, it raises Http404 with 'Directory indexes are not allowed here.' Directory listing is deliberately disabled for security.","triggerScenarios":"Requesting a URL that maps to a directory under the static root, e.g. GET /static/js/ or /static/ with no file portion, or a path whose normalization lands on a directory (e.g. /static/js/../js/).","commonSituations":"Testing the static server by opening a folder URL in a browser; misconfigured base URLs pointing at a directory; broken asset links missing the filename (e.g. /static/css/ instead of /static/css/app.css).","solutions":["Request the actual file path, not the directory, e.g. /static/js/app.js.","Check that asset URLs/href attributes in templates include the filename.","Verify the reverse proxy/CDN is not stripping the filename from the path.","Return 404 gracefully in your error handler and link to a valid index asset if you need an entry page."],"exampleFix":"// before\n<link rel=\"stylesheet\" href=\"/static/css/\">\n\n// after\n<link rel=\"stylesheet\" href=\"/static/css/main.css\">","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\nimport posixpath\ndef is_file_url(static_base, url):\n    path = posixpath.normpath(urlparse(url).path).rstrip('/')\n    return path.startswith(static_base) and posixpath.basename(path) != ''","typeGuard":"import posixpath\ndef points_to_file(path: str) -> bool:\n    return posixpath.basename(posixpath.normpath(path)) != ''","tryCatchPattern":"from django.http import Http404\ntry:\n    return serve(request, path, document_root)\nexcept Http404 as e:\n    logging.warning('Static 404: %s (%s)', path, e)\n    return HttpResponseNotFound('Asset not found')","preventionTips":["Never link bare directory URLs in templates or docs","Assert in tests that every referenced static path ends in a filename","Check reverse-proxy rewrite rules for path stripping"],"tags":["http-404","static-files","django","security"],"backgroundTag":"static-file-not-found","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}