Having trouble translating blob file into image on NextJS App from MongoDB

Summary

The core issue is an “Invalid URL” error triggered when the Next.js Image component attempts to process a malformed image source path. The error arises because the backend API is returning relative paths for image files (likely stored as GridFS or Binary data, converted to strings), and the frontend logic attempts to construct an absolute URL without properly handling cases where the path is empty, null, or undefined. The service.images?.[0] accessor passes undefined to the src prop, causing the URL constructor to fail.

Root Cause

The root cause is insufficient defensive programming and data type handling between the API response and the React component. Specifically:

  • The service.images?.[0] array access can return undefined if the images array is empty or the property is missing.
  • The Image component’s src prop receives this undefined value.
  • The code attempts to check image!.startsWith("http") on a potentially undefined value (though the ! operator assumes existence, runtime behavior differs).
  • When the image path is a relative string (e.g., /uploads/service_1.jpg) and the fallback concatenation http://localhost:3100${image} is used, Next.js Image component requires specific next.config.js hostname configuration for external URLs. If the local development URL is not added to the next.config.js, Next.js optimization fails and throws “Invalid URL”.

Why This Happens in Real Systems

This is a classic TypeScript/JavaScript type safety failure in a full-stack environment.

  • Statically Typed Frontend vs. Dynamic Backend: TypeScript interfaces define images as string[], but runtime data from MongoDB (via Node.js) often returns null, undefined, or empty arrays.
  • Missing next.config.js Setup: In Next.js, using the next/image component requires explicit domain whitelisting for external images (images served from a different origin, such as your Node.js API running on port 3100). Without this configuration, Next.js refuses to proxy the image, resulting in a URL construction error.
  • Blob vs. URL Confusion: The code mixes handling of blob: URLs (client-side file input) and HTTP URLs (server-side storage), leading to conditional logic that fails if the data shape changes.

Real-World Impact

  • Broken UI: The image fails to render, leaving empty white spaces or broken image icons on the service cards.
  • Application Crash: The “Failed to construct ‘URL'” error can propagate, potentially causing the entire component to unmount or display error boundaries if not caught.
  • Poor User Experience: Users perceive the site as broken or slow.
  • Debugging Overhead: Developers spend time tracing the full stack (MongoDB -> Node.js -> Next.js) to find where the data string was malformed.

Example or Code

The fix involves guarding against undefined values and ensuring the Next.js configuration allows local images.

1. Fix the ServiceCard Component:

import Image from "next/image";

interface ServiceCardProps {
  image?: string;
  blob?: string;
  title: string;
  price: number;
  actualPrice?: number;
  description?: string;
}

const ServiceCard: React.FC = ({
  image,
  blob,
  title,
  price,
  actualPrice,
  description,
}) => {
  // 1. Check if we have a valid source
  const hasSource = Boolean(blob || image);

  // 2. Determine the source type
  const isBlob = blob && blob.startsWith("blob:");

  // 3. Construct the URL safely
  let imgSrc = "";
  if (isBlob) {
    imgSrc = blob;
  } else if (image) {
    // Only prepend localhost if it's a relative path
    imgSrc = image.startsWith("http") ? image : `http://localhost:3100${image}`;
  }

  return (
    
{/* Image Section */} {hasSource && (
{isBlob ? ( {title} ) : ( imgSrc && ( ) )}
)} {/* Content Section */}

{title}

{description && (

{description}

)}
AED {price} {actualPrice && actualPrice > price && ( AED {actualPrice} )}
); }; export default ServiceCard;

2. Next.js Configuration (next.config.js):
You must whitelist the domain serving the images.

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'http',
        hostname: 'localhost',
        port: '3100',
        pathname: '/**',
      },
    ],
  },
};

module.exports = nextConfig;

How Senior Engineers Fix It

Senior engineers implement a “Defensive Coding” strategy and standardize image handling.

  1. Validate API Data: They ensure the API layer (Node.js) sanitizes data before sending it to the frontend. If an image field is missing, explicitly set it to null or a default placeholder string, rather than leaving it undefined.
  2. Frontend Guards: They strictly check for existence before accessing properties (e.g., if (service.images && service.images.length > 0)) rather than relying on optional chaining that returns undefined.
  3. Centralize Image Logic: They create a utility function to format image URLs so the logic localhost:3100 + path isn’t repeated in every component, reducing the risk of inconsistent URL construction.
  4. Environment Variables: They replace hardcoded localhost:3100 strings with environment variables (e.g., NEXT_PUBLIC_API_URL) to ensure consistency across development and production.

Why Juniors Miss It

Juniors often focus on the logic flow but overlook type coercion and framework-specific constraints.

  • TypeScript False Sense of Security: Juniors might rely heavily on ! (non-null assertion) operators without understanding that they only suppress compile-time errors, not runtime errors.
  • Framework Configuration Gaps: The requirement to whitelist domains in next.config.js for the next/image component is a common “gotcha” in Next.js that juniors often miss until they deploy or encounter specific URL errors.
  • Debugging Scope: They might look only at the React component code or only at the Node.js API code, failing to realize the error originates from how Next.js constructs the URL internally based on the provided src prop.