github/github-mcp-server · error
provide either 'visible_fields' or 'visible_field_names', no
Error message
provide either 'visible_fields' or 'visible_field_names', not both
What it means
Third guard of validateBlamePath for get_file_blame: the path is split on '/' and rejected if any segment equals "..". This blocks parent-directory traversal before any network call. GitHub's blame would simply find no match for such a path, so the server rejects it locally with 'path must not contain '..' segments'.
Source
Thrown at pkg/github/projects.go:2055
}
func projectViewVisibleFieldsInput(ctx context.Context, gqlClient *githubv4.Client, args map[string]any, owner, ownerType string, projectNumber int) (*ProjectV2ViewConfigurationInput, error) {
_, hasVisibleFields := args["visible_fields"]
_, hasVisibleFieldNames := args["visible_field_names"]
if !hasVisibleFields && !hasVisibleFieldNames {
return nil, nil
}
databaseIDs, err := OptionalBigIntArrayParam(args, "visible_fields")
if err != nil {
return nil, err
}
names, err := OptionalStringArrayParam(args, "visible_field_names")
if err != nil {
return nil, err
}
if len(databaseIDs) > 0 && len(names) > 0 {
return nil, errors.New("provide either 'visible_fields' or 'visible_field_names', not both")
}
if len(databaseIDs) == 0 && len(names) == 0 {
return &ProjectV2ViewConfigurationInput{VisibleFieldIDs: []githubv4.ID{}}, nil
}
all, err := listAllProjectFields(ctx, gqlClient, owner, ownerType, projectNumber)
if err != nil {
return nil, err
}
var resolved []ResolvedField
if len(names) > 0 {
resolved, err = resolveFieldsByName(all, owner, projectNumber, names, "visible_fields")
if err != nil {
return nil, err
}
} else {
byDatabaseID := make(map[int64]ResolvedField, len(all))View on GitHub (pinned to 0ea1f775a7)
Solutions
- Resolve and clean the path first, then re-express it relative to the repository root
- Reject user input containing '..' before it reaches the tool
- Use the final normalized path (e.g. "src/main.go") directly
Example fix
// before
{"owner":"octocat","repo":"Hello-World","path":"docs/../src/main.go"}
// after
{"owner":"octocat","repo":"Hello-World","path":"src/main.go"} Defensive patterns
Strategy: validation
Validate before calling
func hasTraversal(p string) bool {
return slices.Contains(strings.Split(p, "/"), "..")
} Type guard
func isBlamePathError(err error) bool {
return err != nil && strings.HasPrefix(err.Error(), "path must")
} Try / catch
if hasTraversal(path) {
clean, err := filepath.Rel(repoRoot, filepath.Join(repoRoot, path))
if err != nil || hasTraversal(clean) {
return nil, fmt.Errorf("unresolvable path: %s", path)
}
path = clean
}
res, _, err := callGetFileBlame(ctx, buildArgs(owner, repo, path)) Prevention
- Always resolve user paths against the repo root, then re-express relatively
- Reject '..' in untrusted input before it reaches any tool
- Prefer storing canonical repo-relative paths over composing them at call time
- Mirror the server's split-on-slash segment check client-side
When it happens
Trigger: Passing "docs/../src/main.go" or "../other/file.go"; paths produced by filepath.Join with user input containing '..'; normalizing a path that escapes the repository root.
Common situations: Client code combining user-supplied relative paths with '..' components; converting between absolute local paths and repo-relative ones without cleaning; LLM callers echoing filesystem-style paths.
Related errors
- authorization prompt has expired
- authorization did not complete
- response did not include the deleted project view
- installation token response did not contain a token
- installation token response did not contain an expiry
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/f0a791839f9d8597.
Report an issue: GitHub.