gethomepage/homepage · error · Error

content must be a string

Error message

content must be a string

What it means

Thrown by write_config_file when the `content` argument is not a string. Homepage writes the value verbatim to the config file, so it must already be valid YAML/CSS/JS text — objects or other types are rejected before the write to avoid corrupting config.

Source

Thrown at src/utils/mcp/homepage-mcp.js:409

  switch (name) {
    case "list_config_files":
      return textContent(JSON.stringify({ configDir: CONF_DIR, files: listConfigFiles() }, null, 2));
    case "read_config_file": {
      assertKnownConfigFile(args.file);
      return textContent(readConfig(args.file));
    }
    case "validate_config_file": {
      assertKnownConfigFile(args.file);
      const content = Object.prototype.hasOwnProperty.call(args, "content") ? args.content : readConfig(args.file);
      return textContent(JSON.stringify(validateYaml(args.file, content), null, 2));
    }
    case "write_config_file": {
      const disabled = ensureWriteEnabled();
      if (disabled) return disabled;

      assertKnownConfigFile(args.file);
      if (typeof args.content !== "string") {
        throw new Error("content must be a string");
      }
      const validation = validateYaml(args.file, args.content);
      if (!validation.valid) {
        return {
          isError: true,
          ...textContent(JSON.stringify(validation, null, 2)),
        };
      }
      mkdirSync(CONF_DIR, { recursive: true });
      writeFileSync(configPath(args.file), args.content, "utf8");
      return textContent(
        JSON.stringify({ written: args.file, bytes: Buffer.byteLength(args.content, "utf8") }, null, 2),
      );
    }
    case "add_service":
      return addService(args);
    case "add_info_widget":
      return addInfoWidget(args);

View on GitHub (pinned to b6dca1ae03)

Solutions

  1. Pass content as a string containing valid YAML (or CSS/JS for custom files).
  2. If you have a JS object, stringify it with js-yaml's dump (or JSON.stringify for non-YAML) before calling.
  3. To validate without writing, use validate_config_file with the same string content first.
  4. Ensure HOMEPAGE_MCP_ALLOW_WRITE=true is set or the tool returns a 'writing disabled' result before this check.

Example fix

// before
{ "file": "services.yaml", "content": [{ Infra: [] }] }

// after
{ "file": "services.yaml", "content": "- Infra: []\n" }
Defensive patterns

Strategy: type-guard

Validate before calling

function ensureContentString(content) {
  if (typeof content !== 'string') {
    throw new Error('content must be a string; serialize objects with js-yaml.dump or JSON.stringify');
  }
  return content;
}

Type guard

function isContentString(v) {
  return typeof v === 'string';
}

Prevention

When it happens

Trigger: write_config_file tool called with args.file valid but `typeof args.content !== 'string'`. Typical: caller sends a JSON object expecting the server to serialize it, sends a number/boolean, or omits content (and the field isn't handled by the optional branch above).

Common situations: MCP client serializes a config object instead of YAML-stringifying it; caller assumes the server accepts structured data; client omits content thinking the tool reads from elsewhere; templating engine emits a non-string.

Related errors


AI-assisted analysis of gethomepage/homepage@b6dca1ae03 (2026-08-13). Data as JSON: /api/errors/f72cb454ae9dd438. Report an issue: GitHub.