googleapis/mcp-toolbox · error

failed to get documents: %w

Error message

failed to get documents: %w

What it means

Thrown by Source.GetDocuments when FirestoreClient().GetAll(ctx, docRefs) fails while fetching documents by their paths. The raw client error is wrapped so the original gRPC status (permission denied, not found, invalid document path, unavailable) is preserved. It indicates the batch read itself failed, not result conversion.

Source

Thrown at internal/sources/firestore/firestore.go:292

		}

		metricsData["executionStats"] = executionStats
	}

	return metricsData, nil
}

func (s *Source) GetDocuments(ctx context.Context, documentPaths []string) ([]any, error) {
	// Create document references from paths
	docRefs := make([]*firestore.DocumentRef, len(documentPaths))
	for i, path := range documentPaths {
		docRefs[i] = s.FirestoreClient().Doc(path)
	}

	// Get all documents
	snapshots, err := s.FirestoreClient().GetAll(ctx, docRefs)
	if err != nil {
		return nil, fmt.Errorf("failed to get documents: %w", err)
	}

	// Convert snapshots to response data
	results := make([]any, len(snapshots))
	for i, snapshot := range snapshots {
		docData := make(map[string]any)
		docData["path"] = documentPaths[i]
		docData["exists"] = snapshot.Exists()

		if snapshot.Exists() {
			docData["data"] = snapshot.Data()
			docData["createTime"] = snapshot.CreateTime
			docData["updateTime"] = snapshot.UpdateTime
			docData["readTime"] = snapshot.ReadTime
		}

		results[i] = docData
	}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Inspect the wrapped cause; if 'permission denied', grant roles/datastore.user to the service account.
  2. Validate every path is a full doc path like collection/doc/collection2/doc2 — GetAll requires complete document paths.
  3. Confirm the database id in the source config exists (gcloud firestore databases list).
  4. If UNAVAILABLE/DEADLINE_EXCEEDED, retry with backoff or extend the context deadline.
  5. Check project/network configuration (emulator vs production, quotas) if errors persist.

Example fix

// before
paths := []string{"users/"}
res, err := source.GetDocuments(ctx, paths)
// after
paths := []string{"users/user123"}
res, err := source.GetDocuments(ctx, paths)
Defensive patterns

Strategy: validation

Validate before calling

// Go
func validateDocPaths(paths []string) error {
    for _, p := range paths {
        if p == "" || strings.HasPrefix(p, "/") || strings.HasSuffix(p, "/") {
            return fmt.Errorf("invalid document path %q", p)
        }
        if len(strings.Split(p, "/"))%2 != 0 {
            return fmt.Errorf("path %q has odd segments; a document id is missing", p)
        }
    }
    return nil
}

Type guard

func isValidDocPath(p string) bool {
    segs := strings.Split(p, "/")
    return len(segs) >= 2 && len(segs)%2 == 0 && !slices.Contains(segs, "")
}

Try / catch

snapshots, err := source.GetDocuments(ctx, paths)
if err != nil {
    if strings.Contains(err.Error(), "permission denied") {
        return nil, fmt.Errorf("check service account IAM roles/datastore.user: %w", err)
    }
    return nil, fmt.Errorf("get documents failed: %w", err)
}

Prevention

When it happens

Trigger: Calling GetDocuments with malformed document paths (wrong collection/document nesting depth, missing document ID segment), paths the caller has no permission to read, an unreachable Firestore backend, or FirestoreClient being uninitialized.

Common situations: IAM changes removing datastore.user from the service account, hand-constructed paths like 'users/' missing a document ID, pointing the source at a database id that doesn't exist, transient gRPC outages.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/429558a810ce0e27. Report an issue: GitHub.