Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/build/virtual/routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ const multiHandler = (...handlers) => {

${allHandlers
.filter((h) => !h.lazy)
.map((h) => /* js */ `import ${h._importHash} from "${h.handler}";`)
.map(
(h) =>
/* js */ `const ${h._importHash} = await import("${h.handler}").then(m => m.default).catch(() => {})`
)
Comment on lines +33 to +36
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | πŸ”΄ Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

node --input-type=module <<'EOF'
const noDefault = await import('data:text/javascript,export const handler = () => {}');
console.log('default in namespace:', 'default' in noDefault, 'value:', noDefault.default);

try {
  const { default: handler } = await import('data:text/javascript,throw new Error("boom")').catch(() => {});
  console.log('handler:', handler);
} catch (error) {
  console.error('error after catch:', error.message);
}
EOF

Repository: nitrojs/nitro

Length of output: 221


🏁 Script executed:

cd src/build/virtual && [ -f routing.ts ] && cat -n routing.ts | head -50

Repository: nitrojs/nitro

Length of output: 2158


🏁 Script executed:

rg "\.catch\(\(\)" src/build/virtual/routing.ts -A 2 -B 2

Repository: nitrojs/nitro

Length of output: 194


🏁 Script executed:

git ls-files src/build/virtual/

Repository: nitrojs/nitro

Length of output: 506


🏁 Script executed:

rg "\.catch\s*\(\s*\(\s*\)\s*=>\s*\{\s*\}" src/build --type ts

Repository: nitrojs/nitro

Length of output: 185


🏁 Script executed:

rg "await import.*catch" src/build --type ts -A 1 -B 1

Repository: nitrojs/nitro

Length of output: 258


🏁 Script executed:

rg "handler.*import" src/build/virtual/routing.ts -A 2 -B 2

Repository: nitrojs/nitro

Length of output: 39


🏁 Script executed:

git log --oneline src/build/virtual/routing.ts | head -5

Repository: nitrojs/nitro

Length of output: 83


🏁 Script executed:

git show 1b13f32 --stat

Repository: nitrojs/nitro

Length of output: 50369


🏁 Script executed:

git show 1b13f32 -- src/build/virtual/routing.ts | head -80

Repository: nitrojs/nitro

Length of output: 2734


Don't silently swallow handler import failures with .catch(() => {}).

Line 35 suppresses import errors and leaves the destructuring to fail later with an opaque message. When import() succeeds but has no default export, the destructuring still fails downstream without context about which handler path failed. This violates the coding guideline to prefer explicit errors and include actionable context.

Validate mod.default explicitly after import and throw with the handler path included:

Proposed fix
 ${allHandlers
   .filter((h) => !h.lazy)
   .map(
-    (h) =>
-      /* js */ `const { default: ${h._importHash} } = await import("${h.handler}").catch(() => {})`
+    (h) =>
+      /* js */ `
+const ${h._importHash}Module = await import("${h.handler}").catch((error) => {
+  throw new Error(${JSON.stringify(`Failed to import route handler "${h.handler}"`)} + ": " + String(error));
+});
+if (${h._importHash}Module.default === undefined) {
+  throw new Error(${JSON.stringify(`Route handler "${h.handler}" must have a default export`)});
+}
+const ${h._importHash} = ${h._importHash}Module.default;`
   )
   .join("\n")}
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.map(
(h) =>
/* js */ `const { default: ${h._importHash} } = await import("${h.handler}").catch(() => {})`
)
.map(
(h) =>
/* js */ `
const ${h._importHash}Module = await import("${h.handler}").catch((error) => {
throw new Error(${JSON.stringify(`Failed to import route handler "${h.handler}"`)} + ": " + String(error));
});
if (${h._importHash}Module.default === undefined) {
throw new Error(${JSON.stringify(`Route handler "${h.handler}" must have a default export`)});
}
const ${h._importHash} = ${h._importHash}Module.default;`
)
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/build/virtual/routing.ts` around lines 33 - 36, The generated import line
currently swallows all import errors via .catch(() => {}) and then destructures
default into ${h._importHash}, which hides whether the import failed or returned
no default; change the generated code so you import into a module variable
(e.g., const mod = await import("${h.handler}").catch((e) => { throw new
Error(`Failed to import handler ${h.handler}: ${e?.message||e}`); });), then
explicitly validate that mod && mod.default exists before assigning to
${h._importHash} and if not throw a clear error mentioning the handler path and
import hash (use h.handler and h._importHash) so failures surface with
actionable context.

.join("\n")}

${allHandlers
Expand Down
Loading