garrytan/gstack · error · Error
Skill name is empty.
Error message
Skill name is empty.
What it means
Thrown by validateSkillName when the name is falsy (empty string, undefined coerced to '', or any value where `!name` is true). This is the first guard in the skill-write pipeline (stageSkill and commitSkill both call validateSkillName first), so any /skillify flow or programmatic caller that fails to supply a name hits this before any filesystem touch.
Source
Thrown at browse/src/browser-skill-write.ts:37
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { mkdirSecure } from './file-permissions';
import { isPathWithin } from './platform';
import type { TierPaths } from './browser-skills';
import { defaultTierPaths } from './browser-skills';
// ─── Naming validation ──────────────────────────────────────────
/**
* Skill names must be safe directory names: lowercase letters, digits, dashes.
* Starts with a letter, no consecutive dashes, no trailing dash, ≤64 chars.
* Rejects '..', leading dots, slashes, anything that could escape the tier dir.
*/
const SKILL_NAME_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
export function validateSkillName(name: string): void {
if (!name) throw new Error('Skill name is empty.');
if (name.length > 64) throw new Error(`Skill name too long (${name.length} > 64).`);
if (!SKILL_NAME_PATTERN.test(name)) {
throw new Error(
`Invalid skill name "${name}". Must be lowercase letters/digits/dashes, ` +
`start with a letter, no leading/trailing/consecutive dashes.`,
);
}
}
// ─── Staging ────────────────────────────────────────────────────
export interface StageSkillOptions {
name: string;
/** Map of relative path → contents. Path may contain '/' for nested dirs. */
files: Map<string, string | Buffer>;
/** Optional override (tests pass synthetic spawn ids). */
spawnId?: string;
/** Optional override (tests pass a fake tmp root). */View on GitHub (pinned to 94993f7401)
Solutions
- Supply a non-empty name matching the SKILL_NAME_PATTERN.
- Derive the name from the skill's host or purpose before calling stageSkill/commitSkill.
- If the name comes from agent output, validate and re-prompt when empty.
Example fix
// before
stageSkill({ name: '', files: ... });
// after
stageSkill({ name: 'hn-frontpage', files: ... }); Defensive patterns
Strategy: validation
Validate before calling
function requireNonEmptyName(name: unknown): asserts name is string {
if (typeof name !== 'string' || name.length === 0) {
throw new Error('Skill name is empty.');
}
}
// before stageSkill/commitSkill:
requireNonEmptyName(opts.name); Type guard
const isNonEmptyString = (x: unknown): x is string => typeof x === 'string' && x.length > 0;
Prevention
- Derive skill names from deterministic sources (host, purpose) rather than free-form agent text.
- Validate at the boundary — the earliest point the name enters your code.
- Unit-test the empty-name path in any wrapper around stageSkill/commitSkill.
When it happens
Trigger: validateSkillName(''), validateSkillName(undefined as any), or stageSkill({name: '', ...}) / commitSkill({name: '', ...}). Also reachable by directly importing and calling validateSkillName from a test or downstream tool.
Common situations: Agent's /skillify flow derived the name from a heading that came back empty; a templating step stripped the name; programmatic caller passed undefined where a name was expected; a wrapper script consumed the name from an env var that was unset.
Related errors
- Invalid skill name "${name}". Must be lowercase letters/digi
- stageSkill: files map is empty.
- Invalid file path in stageSkill: "${relPath}".
- commitSkill: staged path "${opts.stagedDir}" is not a direct
- Usage: $B skill show <name>
AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12).
Data as JSON: /api/errors/e9052011efc746f5.
Report an issue: GitHub.