googleapis/mcp-toolbox · error

error writing SKILL.md: %w

Error message

error writing SKILL.md: %w

What it means

This error wraps a failure from os.WriteFile when writing the generated SKILL.md file into the skill directory. The markdown content was generated successfully, but persisting it to disk failed — a filesystem-level problem analogous to error 66 but targeting SKILL.md specifically.

Source

Thrown at cmd/internal/skills/command.go:236

			scriptFilename := filepath.Join(scriptsPath, fmt.Sprintf("%s.js", toolName))
			if err := os.WriteFile(scriptFilename, []byte(scriptContent), 0755); err != nil {
				errMsg := fmt.Errorf("error writing script %s: %w", scriptFilename, err)
				opts.Logger.ErrorContext(ctx, errMsg.Error())
				return errMsg
			}
		}

		// Generate SKILL.md
		skillContent, err := generateSkillMarkdown(skillName, content.description, cmd.additionalNotes, allTools, parser.EnvVars)
		if err != nil {
			errMsg := fmt.Errorf("error generating SKILL.md content: %w", err)
			opts.Logger.ErrorContext(ctx, errMsg.Error())
			return errMsg
		}
		skillMdPath := filepath.Join(skillPath, "SKILL.md")
		if err := os.WriteFile(skillMdPath, []byte(skillContent), 0644); err != nil {
			errMsg := fmt.Errorf("error writing SKILL.md: %w", err)
			opts.Logger.ErrorContext(ctx, errMsg.Error())
			return errMsg
		}

		opts.Logger.InfoContext(ctx, fmt.Sprintf("Successfully generated skill '%s' with %d tools.", skillName, len(allTools)))
	}

	return nil
}

// resolveSkillName returns the explicit --name when set. Otherwise, in the
// single-skill modes it defaults to the --group or --toolset name, and for
// prebuilt generation it defaults to the config name when exactly one
// --prebuilt config is given. Any other case requires --name.
func resolveSkillName(name, group, toolset string, prebuiltConfigs []string) (string, error) {
	if name != "" {
		return name, nil
	}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Check permissions on the skill directory and any existing SKILL.md (ls -l) and chmod/chown as needed
  2. Remove or fix a pre-existing SKILL.md with restrictive permissions
  3. Re-run with a different --output location you have write access to
  4. Free disk space or remount read-write if the filesystem is full or read-only

Example fix

// before
-r--r--r-- SKILL.md  # read-only file -> write fails
// after
chmod u+w SKILL.md && toolbox skills --name my-skill ...
Defensive patterns

Strategy: validation

Validate before calling

# Ensure the skill dir exists and SKILL.md is writable before generating
mkdir -p "$OUT/skills/my-skill"
if [ -e "$OUT/skills/my-skill/SKILL.md" ] && [ ! -w "$OUT/skills/my-skill/SKILL.md" ]; then
  chmod u+w "$OUT/skills/my-skill/SKILL.md" || exit 1
fi

Try / catch

try {
  execSync("toolbox skills --name my-skill", { stdio: "inherit" });
} catch (e) {
  if (String(e.stderr).includes("error writing SKILL.md")) {
    console.error("Could not write SKILL.md; fix permissions or output path:", e.stderr);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Running `toolbox skills` when os.WriteFile(skillMdPath, ...) fails — the skill directory is missing, not writable, SKILL.md already exists with restrictive permissions, or the filesystem is full/read-only.

Common situations: The skill directory exists but is owned by root or another user; SKILL.md is checked into git with read-only mode or was edited with restrictive permissions; writing into a read-only container volume or a full disk.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/baf1ccff90a862a6. Report an issue: GitHub.