fix: getFileExtension returns raw URL path instead of null for URLs without file extensions
Author: cax6505Created Jul 31, 2026Updated Aug 19, 2026
Description
In @dub/utils, the getFileExtension(url) helper function incorrectly returns the full URL pathname (e.g. "/AVATAR" or "/API/V1/USERS") when given a URL that does not contain a file extension.
Reproduction
import { getFileExtension } from "@dub/utils";
console.log(getFileExtension("https://dub.co/avatar"));
// Output: "/AVATAR" (Expected: null)
console.log(getFileExtension("https://dub.co/api/v1/users"));
// Output: "/API/V1/USERS" (Expected: null)Cause
In packages/utils/src/functions/urls.ts:
export const getFileExtension = (url: string): string | null => {
try {
const pathname = new URL(url).pathname;
const extension = pathname.split(".").pop(); // When pathname has no ".", returns entire pathname
return extension ? extension.toUpperCase() : null;
} catch { ... }
};When pathname has no dot (.), pathname.split(".") yields ["/avatar"]. Calling .pop() returns "/avatar", which is truthy, so it returns "/AVATAR".
Impact
In ResourceCard (resources/page.tsx), brand logos with extensionless asset URLs display badge labels like "/LOGO · 24 KB" instead of "Unknown · 24 KB".
Proposed Fix
Verify that the extracted filename actually contains a dot before returning the extension:
export const getFileExtension = (url: string): string | null => {
try {
const pathname = new URL(url).pathname;
const filename = pathname.split("/").pop() || "";
if (!filename.includes(".")) return null;
const extension = filename.split(".").pop();
return extension && extension !== filename ? extension.toUpperCase() : null;
} catch {
return null;
}
};Source: dubinc/dub