Mintplex-Labs/anything-llm · warning

Image not found in storage

Error message

Image not found in storage

What it means

Returned (HTTP 404) by GET /image-generation/generated-images/:filename when fs.promises.readFile(imagePath) throws — an accessible chat record references the image, but the file is missing from the generatedImagesPath directory (storage/generated-images by default). Authorization already passed; this is purely a disk-level miss, i.e. DB/storage desync.

Source

Thrown at server/endpoints/agentFileServer.js:127

        if (!filename || !GENERATED_IMAGE_FILENAME_PATTERN.test(filename))
          return response.status(400).json({ error: "Invalid filename" });

        const fileSource = await findFileSource(filename, {
          user,
          isMultiUser: multiUserMode(response),
        });
        if (!fileSource)
          return response
            .status(404)
            .json({ error: "Image not found or access denied" });

        const imagePath = path.resolve(generatedImagesPath, filename);
        let imageBuffer;
        try {
          imageBuffer = await fs.promises.readFile(imagePath);
        } catch {
          return response
            .status(404)
            .json({ error: "Image not found in storage" });
        }

        response.setHeader("Content-Type", "image/png");
        return response.send(imageBuffer);
      } catch (error) {
        console.error("[agentFileServer] Image serve error:", error.message);
        return response.status(500).json({ error: "Failed to serve image" });
      }
    }
  );
}

/**
 * Locates the source record (a workspace chat or a scheduled job run) that
 * references the given storage filename, and confirms the requester has access.
 *
 * Search order:

View on GitHub (pinned to 3aec848f28)

Solutions

  1. Confirm storage/generated-images actually contains the img-<uuid>.png file on the serving instance
  2. Align the generated-images path configuration across every instance serving these URLs
  3. Regenerate the image from the chat request
  4. If pruning storage, expect old <img> links to land here — remove the referencing history too
Defensive patterns

Strategy: validation

Validate before calling

// Operator preflight: authorizing record exists AND blob exists on the serving instance
const referenced = await chatHistoryMentions(storageFilename);
const onDisk = fs.existsSync(path.join(generatedImagesPath, storageFilename));
if (referenced && !onDisk) console.warn('orphaned image reference:', storageFilename);

Try / catch

try {
  const res = await fetch(imgUrl, {credentials: 'include'});
  if (res.status === 404) {
    const body = await res.json();
    if (body.error === 'Image not found in storage')
      await regenerateImage(); // record exists, disk does not — nothing else recovers it
  }
} catch (e) { /* network failure */ }

Prevention

When it happens

Trigger: The generated-images directory was pruned while chat rows remain; generatedImagesPath resolves to a different location than where images were written (env or cwd differences — the path is resolved relative to the server); the volume is not mounted in the container serving the request; the file was manually deleted.

Common situations: Cleaning storage folders without cleaning history; moving the app to a new host or changing the storage root; docker deployments with missing volume mounts; restoring a DB backup without the matching storage backup.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18). Data as JSON: /api/errors/cfb043caaf4d447e. Report an issue: GitHub.