googleapis/mcp-toolbox · error
invalid path: expected 'projects', got %q
Error message
invalid path: expected 'projects', got %q
What it means
The page URL path is validated segment-by-segment against the canonical Healthcare API layout (v1/projects/<project>/locations/<location>/datasets/<ds>/fhirStores/<store>/...). This error means segment[1] is not the literal string "projects", so the URL does not follow the required structure and is rejected before any request is made.
Source
Thrown at internal/sources/cloudhealthcare/cloud_healthcare.go:359
}
// Clean and split path
cleanPath := path.Clean(parsed.Path)
// Truncate leading and trailing slashes for easier splitting
trimmed := strings.Trim(cleanPath, "/")
parts := strings.Split(trimmed, "/")
// Page URL format Reference: https://docs.cloud.google.com/healthcare-api/docs/how-tos/fhir-search#using_the_search_method_with_get
if len(parts) < 10 {
return "", fmt.Errorf("invalid FHIR URL path structure: path too short")
}
if !isValidAPIVersion(parts[0]) {
return "", fmt.Errorf("invalid API version prefix: %q", parts[0])
}
if parts[1] != "projects" {
return "", fmt.Errorf("invalid path: expected 'projects', got %q", parts[1])
}
if parts[2] != s.Project() {
return "", fmt.Errorf("invalid project %q: must match source project %q", parts[2], s.Project())
}
if parts[3] != "locations" {
return "", fmt.Errorf("invalid path: expected 'locations', got %q", parts[3])
}
if parts[4] != s.Region() {
return "", fmt.Errorf("invalid location/region %q: must match source region %q", parts[4], s.Region())
}
if parts[5] != "datasets" {
return "", fmt.Errorf("invalid path: expected 'datasets', got %q", parts[5])
}
if parts[6] != s.DatasetID() {
return "", fmt.Errorf("invalid dataset ID %q: must match source dataset %q", parts[6], s.DatasetID())
}
if parts[7] != "fhirStores" {
return "", fmt.Errorf("invalid path: expected 'fhirStores', got %q", parts[7])View on GitHub (pinned to 8cc6e09de2)
Solutions
- Use the exact links.next URL from the previous Google response — it always has "projects" as the second segment
- Remove any proxy path prefixes from the page URL or decode %2F-encoded slashes causing misalignment
- Fix casing: segments are lowercase and case-sensitive ("projects", not "Projects")
- Count the segments: v1(0)/projects(1)/<project>(2)/locations(3)/...
Example fix
// before (proxy prefix shifted segments) page := "https://healthcare.googleapis.com/v1/api/projects/p/locations/l/..." // after (canonical Google path) page := "https://healthcare.googleapis.com/v1/projects/p/locations/l/datasets/d/fhirStores/f/fhir/Patient?pageToken=x"
Defensive patterns
Strategy: validation
Validate before calling
function hasCanonicalSegments(u) { const p = new URL(u).pathname.split('/').filter(Boolean); return p[0]?.startsWith('v') && p[1] === 'projects' && p[3] === 'locations'; } Prevention
- Strip proxy base-path prefixes from page URLs so segments align with the canonical layout
- Use lowercase literal segment names: projects, locations, datasets, fhirStores
- Compare against a captured links.next URL when debugging segment mismatches
When it happens
Trigger: A page URL whose second path segment differs from "projects" — e.g. a relative path that lost its first segments, a URL with the version segment doubled, or a proxy path prefix like /api/projects/... shifting all segments.
Common situations: Reverse proxy base-path prefixes changing segment order; LLM-written URLs with typos ("project" singular, "Projects" capitalized — comparison is case-sensitive); URL-encoding of the segment.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- invalid FHIR URL path structure: path too short
- invalid API version prefix: %q
- invalid page URL: %w
- no document found
- unable to iterate through query results: %w
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/bd814b0bac525677.
Report an issue: GitHub.