gastownhall/beads · error

invalid file type: only .md and .markdown files are…

Error message

invalid file type: only .md and .markdown files are supported

What it means

The markdown import path only accepts files with a `.md` or `.markdown` extension (case-insensitive). validateMarkdownPath inspects filepath.Ext of the cleaned path and rejects anything else, because the parser expects markdown issue templates.

Solutions

  1. Rename the file to end in .md or .markdown
  2. Copy the content into a new .md file and import that
  3. If it is markdown under another extension, create a symlink/copy with a .md name

Example fix

// before
parseMarkdownFile("issues.txt")
// after
parseMarkdownFile("issues.md")   // or: cp issues.txt issues.md
Defensive patterns

Strategy: validation

Validate before calling

ext := strings.ToLower(filepath.Ext(path))
if ext != ".md" && ext != ".markdown" {
	return fmt.Errorf("%s is not a markdown file", path)
}

Prevention

When it happens

Trigger: Passing a file with any other extension (e.g. `.txt`, `.mdown`, `.MD` is fine but `.markdown5` is not) or no extension to the markdown import API.

Common situations: Importing a `.txt` issue dump; a generated temp file with a random suffix; renaming scripts stripping the extension; Windows files created without extension.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/a33e2f9e939ae007. Report an issue: GitHub.

Appendix: source

Thrown at cmd/bd/markdown.go:119

		issue.Dependencies = parseDependencies(content)
	}
}

// validateMarkdownPath validates and cleans a markdown file path to prevent security issues.
// It checks for directory traversal attempts and ensures the file is a markdown file.
func validateMarkdownPath(path string) (string, error) {
	// Clean the path
	cleanPath := filepath.Clean(path)

	// Prevent directory traversal
	if strings.Contains(cleanPath, "..") {
		return "", fmt.Errorf("invalid file path: directory traversal not allowed")
	}

	// Ensure it's a markdown file
	ext := strings.ToLower(filepath.Ext(cleanPath))
	if ext != ".md" && ext != ".markdown" {
		return "", fmt.Errorf("invalid file type: only .md and .markdown files are supported")
	}

	// Check file exists and is not a directory
	info, err := os.Stat(cleanPath)
	if err != nil {
		return "", fmt.Errorf("cannot access file: %w", err)
	}
	if info.IsDir() {
		return "", fmt.Errorf("path is a directory, not a file")
	}

	return cleanPath, nil
}

// parseMarkdownFile parses a markdown file and extracts issue templates.
// Expected format:
//
//	## Issue Title

View on GitHub (pinned to 71377f2769)