cli/cli · error

invalid repository URL %q: %w

Error message

invalid repository URL %q: %w

What it means

ParseRepoURL delegates parsing to ghrepo.FromFullName, which accepts forms like "OWNER/REPO", "https://github.com/OWNER/REPO", and "OWNER/REPO@ref". When the non-empty input does not match any accepted shape (wrong segment count, bad URL, extra path components), the parse error is wrapped with the offending raw value included for diagnosis.

Source

Thrown at internal/skills/source/source.go:28

)

const SupportedHost = "github.com"

// BuildRepoURL returns the canonical repository URL stored in skill metadata.
func BuildRepoURL(host, owner, repo string) string {
	return ghrepo.GenerateRepoURL(ghrepo.NewWithHost(owner, repo, host), "")
}

// ParseRepoURL parses a repository URL stored in skill metadata.
func ParseRepoURL(raw string) (ghrepo.Interface, error) {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return nil, fmt.Errorf("repository URL is empty")
	}

	repo, err := ghrepo.FromFullName(raw)
	if err != nil {
		return nil, fmt.Errorf("invalid repository URL %q: %w", raw, err)
	}

	return repo, nil
}

// ParseMetadataRepo extracts repository information from skill metadata.
func ParseMetadataRepo(meta map[string]interface{}) (ghrepo.Interface, bool, error) {
	if meta == nil {
		return nil, false, nil
	}

	repoValue, _ := meta["github-repo"].(string)
	if repoValue == "" {
		return nil, false, nil
	}

	repo, err := ParseRepoURL(repoValue)
	if err != nil {

View on GitHub (pinned to 0eeec0b92e)

Solutions

  1. Normalize the value to OWNER/REPO (e.g. strip https://host, /tree/main suffixes) and retry
  2. If a URL form is used, ensure it is a well-formed https://github.com/OWNER/REPO link
  3. Print the raw value from the error and fix the producing field (usually github-repo in SKILL.md metadata)

Example fix

# before
github-repo: octocat/my-repo/tree/main   # invalid repository URL

# after
github-repo: octocat/my-repo
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check shape: 1 or 2 non-empty segments, optional scheme+host
parts := strings.Split(strings.TrimPrefix(raw, "https://github.com/"), "/")
if len(parts) < 1 || len(parts) > 2 || parts[0] == "" {
	return fmt.Errorf("expected OWNER/REPO form, got %q", raw)
}

Try / catch

repo, err := source.ParseRepoURL(raw)
if err != nil {
	// err already includes the raw value; log it and reject the metadata
	return fmt.Errorf("rejecting skill metadata: %w", err)
}

Prevention

When it happens

Trigger: Passing strings like "owner" (one segment), "a/b/c/d" (too many segments), "https://github.com" (no owner/repo), values with spaces or control characters, or URLs on unexpected hosts with malformed paths.

Common situations: Hand-edited skill metadata with typos; scripts composing repo strings with a missing slash or an appended branch name in the wrong place; copy-paste of browser URLs that include extra path segments like /tree/main.

Related errors


AI-assisted analysis of cli/cli@0eeec0b92e (2026-08-15). Data as JSON: /api/errors/2b39716c942a4471. Report an issue: GitHub.