Skip to content
cccskills
FreePublished on GitHub

vite-proxy-folder-name-conflict

Fix 404 errors for frontend JS files when using Vite proxy. Use when: (1) Browser shows "Failed to load resource: 404" for JS/JSX files that exist on disk, (2) Vite serves HTML instead of JavaScript for module imports, (3) You have a client folder named "api" (or similar) AND a Vite proxy configured for "/api". The proxy intercepts requests for client-side files when folder names match proxy paths. Applies to Vite, Vite+React, Vite+Vue projects with dev server proxy configuration.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md5.3 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Vite Proxy Folder Name Conflict

Problem

Frontend JavaScript/JSX files return 404 errors even though they exist on disk. The browser console shows errors like:

usePeople.js:1 Failed to load resource: the server responded with a status of 404 (Not Found)
useMedia.js:1 Failed to load resource: the server responded with a status of 404 (Not Found)

The files exist at paths like src/client/api/hooks/usePeople.js, but Vite returns 404 or serves HTML instead of JavaScript.

Context / Trigger Conditions

This issue occurs when ALL of these conditions are true:

  1. Vite dev server with proxy configuration in vite.config.js:

    server: {
      proxy: {
        '/api': {
          target: 'http://localhost:3001',
          changeOrigin: true,
        },
      },
    }
    
  2. Client-side folder with the same name as the proxy path:

    src/client/
    ├── api/           ← Folder name matches proxy path "/api"
    │   ├── client.js
    │   └── hooks/
    │       ├── usePeople.js
    │       └── useMedia.js
    
  3. Imports that resolve to the proxied path:

    // In src/client/pages/Directory.jsx
    import { usePeople } from '../api/hooks/usePeople.js';
    // Vite transforms this to: /api/hooks/usePeople.js
    // This matches the proxy rule and gets sent to backend!
    

Root Cause

Vite's module resolution transforms relative imports to absolute paths. When you import ../api/hooks/usePeople.js from a page, Vite resolves it to /api/hooks/usePeople.js.

The proxy configuration matches paths starting with /api and forwards them to the backend server. Since /api/hooks/usePeople.js starts with /api, it gets proxied to the backend instead of being served as a static file.

The backend doesn't have a route for /api/hooks/usePeople.js, so it returns 404.

Solution

Option 1: Rename the client folder (Recommended)

Rename the conflicting folder to something that won't match the proxy path:

# Rename api to services (or lib, helpers, etc.)
mv src/client/api src/client/services

# Update all imports
find src/client -name "*.jsx" -o -name "*.js" | xargs sed -i '' 's|from.*['"'"'"]\.\.\/api|from "../services|g'

Option 2: Use a different proxy path

Change the proxy path to something more specific:

// vite.config.js
server: {
  proxy: {
    '/api/v1': {  // More specific path
      target: 'http://localhost:3001',
      changeOrigin: true,
    },
  },
}

Option 3: Configure proxy to exclude certain patterns

Use a custom function to exclude certain paths:

server: {
  proxy: {
    '/api': {
      target: 'http://localhost:3001',
      changeOrigin: true,
      bypass: (req) => {
        // Don't proxy requests for JS/TS files
        if (req.url.match(/\.(js|jsx|ts|tsx|mjs)$/)) {
          return req.url;
        }
      },
    },
  },
}

Verification

After applying the fix:

  1. Clear Vite's cache: rm -rf node_modules/.vite
  2. Restart the dev server: npm run dev
  3. Check browser console - 404 errors should be gone
  4. Verify the app loads and API calls still work

Test both:

  • Frontend file serving: curl http://localhost:5173/services/hooks/usePeople.js should return JavaScript
  • API proxying: curl http://localhost:5173/api/people should return JSON from backend

Example

Before (broken):

src/client/
├── api/                    ← Conflicts with proxy
│   └── hooks/
│       └── usePeople.js
├── pages/
│   └── Directory.jsx       ← import from '../api/hooks/usePeople.js'

vite.config.js:
  proxy: { '/api': 'http://localhost:3001' }

Result: Browser gets 404 for usePeople.js

After (fixed):

src/client/
├── services/               ← Renamed to avoid conflict
│   └── hooks/
│       └── usePeople.js
├── pages/
│   └── Directory.jsx       ← import from '../services/hooks/usePeople.js'

vite.config.js:
  proxy: { '/api': 'http://localhost:3001' }  ← Unchanged

Result: Frontend files served correctly, API still proxied

Notes

  • This issue is not specific to React—it affects any Vite project with proxies
  • Common conflicting folder names: api, graphql, socket, ws
  • The issue only manifests in development (Vite dev server); production builds don't have this problem
  • If using TypeScript path aliases, ensure they also avoid proxy path conflicts
  • Always clear Vite's cache (node_modules/.vite) after changing folder structure

Related Issues

  • Similar issues can occur with other dev servers (webpack-dev-server, Create React App)
  • If using a monorepo, check proxy configs in both root and package-level configs

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Fix ArgoCD ExternalSecret deployment failing with "namespace X is not permitted in project Y". Use when: (1) ExternalSecret shows OutOfSync in ArgoCD but won't sync, (2) ArgoCD application status shows "namespace X is not permitted in project 'infrastructure'", (3) ExternalSecret targets a namespace managed by a different ArgoCD project, (4) Using apps-of-apps pattern with separate infrastructure and application projects.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

Art direction for any content — reads text, PDF, Word, HTML, PPT, then proposes 2-3 creative directions with photography style, mood, and visual language. After selection, generates AI image prompts and visual briefs section-by-section. Use when the user shares content and needs visual direction, image sourcing, or creative direction for any material.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

Fix "Null check operator used on a null value" errors when an object is set to null during an async await. Use when: (1) Object reference is nullified while awaiting, (2) Code accesses object with ! after await returns, (3) Cancel/dispose operations run concurrently with async operations on same object. Solution: capture local reference before await.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

Add custom metadata headers (x-amz-meta-*) to AWS v4 signed requests for GCS S3-compatible API. Use when: (1) Adding custom metadata to GCS uploads via S3 API, (2) Getting signature mismatch errors after adding new headers, (3) x-amz-meta-* headers being ignored or causing 403 errors. Custom headers MUST be included in canonical headers and signed headers list.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

Fix password/secret authentication failures caused by trailing newlines when creating Google Cloud secrets (or similar) with bash here-strings. Use when: (1) Password authentication fails with correct password, (2) Secret created with `<<< "value"` syntax, (3) Error like "password authentication failed" or "invalid token" despite correct value. Bash here-strings (`<<<`) add a trailing newline that corrupts secrets.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

Fix silent video/media processing failures caused by URL extraction code that filters on file extensions (.mp4, .webm, .webp). Use when: (1) Media moderation, transcoding, or analysis silently skips files from Blossom or content-addressed storage servers, (2) URL extraction from Nostr event tags (imeta, r tags) drops URLs without recognized extensions, (3) CDN fallback URLs append .mp4 but the actual server uses extensionless content-addressed paths like /{sha256}. Common in Nostr video events (kind 34236) where different clients use different URL formats.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

See all skills by divinevideo

Report a problem with this skill