garrytan/gstack · warning · StrictModeError
image is not a regular file: ${src}
Error message
image is not a regular file: ${src} What it means
StrictModeError thrown when a local image filePath exists and stat succeeds but stat.isFile() is false — i.e. the path is a directory, fifo, character/block device, or socket. Reading such a path could hang readFileSync (fifo) or produce garbage, so the pre-pass guards it; strict makes it fatal, otherwise warn + placeholder.
Source
Thrown at make-pdf/src/diagram-prepass.ts:667
if (!realFilePath.startsWith(inputRoot)) {
const msg = `image resolves OUTSIDE the input directory: ${src} → ${realFilePath}`;
if (opts.strict) throw new StrictModeError(msg + " — move it under the markdown's directory or drop --strict");
opts.warn(msg);
}
// Bound the read BEFORE reading: a markdown image pointing at a special
// file (fifo, device) would hang readFileSync, and a multi-GB file would
// exhaust memory before any policy ran.
let stat: fs.Stats;
try {
stat = fs.statSync(filePath);
} catch {
opts.warn(`image unreadable: ${src}`);
return buildMissingImagePlaceholder(src);
}
if (!stat.isFile()) {
const msg = `image is not a regular file: ${src}`;
if (opts.strict) throw new StrictModeError(msg);
opts.warn(msg);
return buildMissingImagePlaceholder(src);
}
if (stat.size > MAX_IMAGE_BYTES) {
const msg = `image exceeds ${Math.round(MAX_IMAGE_BYTES / 1024 / 1024)}MB cap: ${src} (${Math.round(stat.size / 1024 / 1024)}MB)`;
if (opts.strict) throw new StrictModeError(msg);
opts.warn(msg);
return buildMissingImagePlaceholder(src);
}
let buf = fs.readFileSync(filePath);
let dims = imageDims(buf);
let mime = dims?.mime ?? mimeFromExtension(filePath);
// Print-resolution normalization (D4): rasters only — SVG scales free.
if (dims && mime !== "image/svg+xml" && dims.width > maxPx) {
const tab = opts.getTab();
if (tab) {View on GitHub (pinned to 94993f7401)
Solutions
- Point the markdown src at an actual image file, not a directory or special file.
- Remove any fifo/device node masquerading as an image in the assets folder.
- Drop --strict to degrade to a warn + placeholder if appropriate.
- Audit the assets directory for non-regular files (`find . -type p -o -type b -o -type c`).
Example fix
<!-- before: assets is a directory -->  <!-- after --> 
Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs';
import path from 'node:path';
function findNonRegularImages(markdown: string, inputDir: string): string[] {
const re = /!\[[^\]]*\]\((?!https?:|data:)([^)]+)\)/g;
const bad: string[] = [];
let m: RegExpExecArray | null;
while ((m = re.exec(markdown))) {
const p = path.resolve(inputDir, decodeURIComponent(m[1]));
try { if (!fs.statSync(p).isFile()) bad.push(m[1]); } catch { /* missing handled elsewhere */ }
}
return bad;
} Type guard
import { StrictModeError } from './diagram-prepass';
function isStrictModeError(e: unknown): e is StrictModeError {
return e instanceof StrictModeError;
} Prevention
- Reference image files, not directories.
- Audit assets for special files (`find . \\( -type p -o -type b -o -type c -o -type s \\) -ls`).
- Drop --strict only if you are certain non-regular files are acceptable.
- Validate image extensions against actual file type before committing.
When it happens
Trigger: inlineLocalImages() under --strict where the resolved image path is a directory (e.g.  where assets is a folder), a named pipe, or a device file. The existence check passes (it exists) but stat.isFile() returns false.
Common situations: Markdown accidentally points at a directory (missing filename); a prank/malicious doc referencing /dev/zero or a fifo; a broken build that left a directory where a PNG should be; a path whose extension is .png but is actually a folder.
Related errors
- image not found: ${src} (resolved to ${filePath})
- image resolves OUTSIDE the input directory: ${src} → ${realF
- remote image blocked (offline posture): ${src} — re-run with
- image exceeds ${Math.round(MAX_IMAGE_BYTES / 1024 / 1024)}MB
- Invalid file path in stageSkill: "${relPath}".
AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12).
Data as JSON: /api/errors/f34816b5f5bde5f8.
Report an issue: GitHub.