tobi/qmd · error · Error

handelize: path cannot be empty

Error message

handelize: path cannot be empty

What it means

handelize() converts a path into a handle (safe filename) and rejects empty or whitespace-only input up front, since there is no filename content to build a handle from.

Source

Thrown at src/store.ts:2365

 * - Convert triple underscore `___` to `/` (folder separator)
 * - Replace sequences of non-word chars (except /) with single dash
 * - Remove leading/trailing dashes from path segments
 * - Preserve folder structure (a/b/c/d.md stays structured)
 * - Preserve file extension
 * - Preserve original case (important for case-sensitive filesystems)
 */
/** Replace emoji/symbol codepoints with their hex representation (e.g. 🐘 → 1f418) */
function emojiToHex(str: string): string {
  return str.replace(/(?:\p{So}\p{Mn}?|\p{Sk})+/gu, (run) => {
    // Split the run into individual emoji and convert each to hex, dash-separated
    return [...run].filter(c => /\p{So}|\p{Sk}/u.test(c))
      .map(c => c.codePointAt(0)!.toString(16)).join('-');
  });
}

export function handelize(path: string): string {
  if (!path || path.trim() === '') {
    throw new Error('handelize: path cannot be empty');
  }

  // Allow route-style "$" filenames while still rejecting paths with no usable content.
  // Emoji (\p{So}) counts as valid content — they get converted to hex codepoints below.
  const segments = path.split('/').filter(Boolean);
  const lastSegment = segments[segments.length - 1] || '';
  const filenameWithoutExt = lastSegment.replace(/\.[^.]+$/, '');
  const hasValidContent = /[\p{L}\p{N}\p{So}\p{Sk}$]/u.test(filenameWithoutExt);
  if (!hasValidContent) {
    throw new Error(`handelize: path "${path}" has no valid filename content`);
  }

  const result = path
    .replace(/___/g, '/')       // Triple underscore becomes folder separator
    .split('/')
    .map((segment, idx, arr) => {
      const isLastSegment = idx === arr.length - 1;

View on GitHub (pinned to dbfd0b4736)

Solutions

  1. Check the path is non-empty before calling handelize
  2. Fix the upstream code producing the empty string
  3. Provide a fallback handle name

Example fix

// before
const h = handelize(pathVar); // pathVar === ''
// after
const h = handelize(pathVar || 'untitled');
Defensive patterns

Strategy: validation

Validate before calling

if (!path || !path.trim()) throw new TypeError('path required');

Type guard

const isNonEmptyPath = (p: unknown): p is string => typeof p === 'string' && p.trim().length > 0;

Prevention

When it happens

Trigger: Calling handelize('') or handelize(' ') (or a variable that trims to empty) — e.g. a computed path whose basename was stripped earlier.

Common situations: Passing undefined/null coerced to 'undefined' is fine but empty string from a failed lookup or .replace() is common; default parameters producing '' when config is missing.

Related errors


AI-assisted analysis of tobi/qmd@dbfd0b4736 (2026-08-28). Data as JSON: /api/errors/053309b020174c28. Report an issue: GitHub.