github/spec-kit · error · SystemExit

ERROR: Feature directory not found. Set SPECIFY_FEATURE_DIRE

Error message

ERROR: Feature directory not found. Set SPECIFY_FEATURE_DIRECTORY or run the specify command to create .specify/feature.json.

What it means

When downloading workflow source over HTTP, the downloader reads the Content-Length header; if the server declares more bytes than the cap (max_bytes, tied to _MAX_WORKFLOW_YAML_BYTES = 5 MiB), it raises ValueError immediately without downloading. This is a pre-flight DoS/resource guard for `workflow add`-style URL sources.

Source

Thrown at scripts/python/common.py:167

    elif (repo_root / ".specify" / "feature.json").is_file():
        stored = read_feature_json_feature_directory(repo_root)
        if not stored:
            print(
                "ERROR: Feature directory not found. Set SPECIFY_FEATURE_DIRECTORY "
                "or ensure .specify/feature.json contains feature_directory.",
                file=sys.stderr,
            )
            raise SystemExit(1)
        feature_dir = Path(stored)
        if not feature_dir.is_absolute():
            feature_dir = repo_root / feature_dir
    else:
        print(
            "ERROR: Feature directory not found. Set SPECIFY_FEATURE_DIRECTORY "
            "or run the specify command to create .specify/feature.json.",
            file=sys.stderr,
        )
        raise SystemExit(1)

    if not current_branch:
        current_branch = Path(_trim_trailing_separators(feature_dir)).name

    return FeaturePaths(
        repo_root=repo_root,
        current_branch=current_branch,
        feature_dir=feature_dir,
        feature_spec=feature_dir / "spec.md",
        impl_plan=feature_dir / "plan.md",
        tasks=feature_dir / "tasks.md",
        research=feature_dir / "research.md",
        data_model=feature_dir / "data-model.md",
        quickstart=feature_dir / "quickstart.md",
        contracts_dir=feature_dir / "contracts",
    )

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Verify the URL points to the raw workflow YAML file (e.g. raw.githubusercontent.com/.../workflow.yaml), not an archive or HTML page
  2. If the workflow legitimately exceeds 5 MiB, host a slimmer version — split assets out or minify
  3. Download manually (curl -sI <url> | grep -i content-length) to confirm the real size before blaming the CLI
  4. Add a pre-check in your tooling: HEAD the URL and reject Content-Length over the limit with your own message

Example fix

# before
specify workflow add https://github.com/org/repo/archive/refs/heads/main.zip

# after
specify workflow add https://raw.githubusercontent.com/org/repo/main/.specify/workflows/my-workflow.yaml
Defensive patterns

Strategy: validation

Validate before calling

import urllib.request

MAX = 5 * 1024 * 1024
req = urllib.request.Request(url, method='HEAD')
with urllib.request.urlopen(req) as r:
    length = int(r.headers.get('Content-Length', 0))
if length > MAX:
    raise ValueError(f'workflow source too large: {length} bytes (max {MAX})')

Try / catch

try:
    data = download_workflow_source(url)
except ValueError as e:
    if 'workflow size limit' in str(e):
        raise SystemExit('URL serves something bigger than a workflow file; check the URL points at raw YAML') from e
    raise

Prevention

When it happens

Trigger: `specify workflow add <url>` (or direct use of the download helper) where the URL's response carries Content-Length > 5242880 — e.g. a large generated bundle, a mispointed URL serving a repository tarball, or an HTML error page that is huge.

Common situations: Pointing workflow add at a full GitHub repo archive or release asset instead of the raw workflow YAML; a URL redirect landing on a big page; a CDN serving a bloated bundle; version changes where a workflow grew beyond 5 MiB legitimately.

Related errors


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/b93fd9f20b17cb32. Report an issue: GitHub.