tobi/qmd · error · Error

Failed to write ${configPath}: ${error}

Error message

Failed to write ${configPath}: ${error}

What it means

saveConfig could not write the serialized YAML config to disk; writeFileSync threw (EACCES, ENOSPC, EISDIR, readonly path, etc.) and the error is wrapped with the target path. It is raised by every operation that mutates collections (add/remove/rename, settings updates).

Source

Thrown at src/collections.ts:231

  if (configSource.type === 'inline') {
    configSource.config = config;
    return;
  }

  const configPath = configSource.path || getConfigFilePath();
  const configDir = dirname(configPath);
  if (!existsSync(configDir)) {
    mkdirSync(configDir, { recursive: true });
  }

  try {
    const yaml = YAML.stringify(config, {
      indent: 2,
      lineWidth: 0,  // Don't wrap lines
    });
    writeFileSync(configPath, yaml, "utf-8");
  } catch (error) {
    throw new Error(`Failed to write ${configPath}: ${error}`);
  }
}

/**
 * Get a specific collection by name
 * Returns null if not found
 */
export function getCollection(name: string): NamedCollection | null {
  const config = loadConfig();
  const collection = config.collections[name];

  if (!collection) {
    return null;
  }

  return { name, ...collection };
}

View on GitHub (pinned to dbfd0b4736)

Solutions

  1. Check permissions/ownership of the config path named in the message and chown/chmod it
  2. Free disk space or remount the filesystem read-write
  3. Avoid running qmd with sudo so configs aren't written as root
  4. Pass an explicit writable configPath when running in containers/CI
Defensive patterns

Strategy: try-catch

Validate before calling

import { accessSync, constants } from 'node:fs';
import { dirname } from 'node:path';

function configWritable(configPath: string): boolean {
  try {
    accessSync(dirname(configPath), constants.W_OK);
    return true;
  } catch { return false; }
}

Try / catch

try {
  await store.addCollection?.(name, path);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Failed to write')) {
    // show path, check permissions/disk, surface to user
  } else throw e;
}

Prevention

When it happens

Trigger: Running qmd collection add/remove/rename when the config path is read-only, owned by another user, on a full disk, or when the path is a directory.

Common situations: Configs under a root-owned /etc or ~/.config after running qmd once with sudo; disk-full CI runners; immutable container filesystems; two qmd processes racing on the same config.

Related errors


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