googleapis/mcp-toolbox · error
failed to update document: %w
Error message
failed to update document: %w
What it means
Thrown by Source.UpdateDocument when either docRef.Update(ctx, updates) (partial update path) or docRef.Set(ctx, documentData, firestore.MergeAll) (merge-set path) fails. The write error is wrapped so the gRPC cause is preserved. It means the document was not modified — Firestore writes are atomic, so no partial update was applied.
Source
Thrown at internal/sources/firestore/firestore.go:358
return response, nil
}
func (s *Source) UpdateDocument(ctx context.Context, documentPath string, updates []firestore.Update, documentData any, returnData bool) (map[string]any, error) {
// Get the document reference
docRef := s.FirestoreClient().Doc(documentPath)
// Prepare update data
var writeResult *firestore.WriteResult
var writeErr error
if len(updates) > 0 {
writeResult, writeErr = docRef.Update(ctx, updates)
} else {
writeResult, writeErr = docRef.Set(ctx, documentData, firestore.MergeAll)
}
if writeErr != nil {
return nil, fmt.Errorf("failed to update document: %w", writeErr)
}
// Build the response
response := map[string]any{
"documentPath": docRef.Path,
"updateTime": writeResult.UpdateTime.Format("2006-01-02T15:04:05.999999999Z"),
}
// Add document data if requested
if returnData {
// Fetch the updated document to return the current state
snapshot, err := docRef.Get(ctx)
if err != nil {
return nil, fmt.Errorf("failed to retrieve updated document: %w", err)
}
// Convert the document data to simple JSON format
simplifiedData := FirestoreValueToJSON(snapshot.Data())
response["documentData"] = simplifiedDataView on GitHub (pinned to 8cc6e09de2)
Solutions
- If the cause is 'No document to update', create the document first or use the Set/MergeAll path (omit the updates field).
- Validate field paths: non-empty, no leading/trailing dots, no '..' segments.
- Check the wrapped cause for 'permission denied' and grant roles/datastore.user.
- Keep documents under 1 MiB; split large payloads across subcollections.
- Retry on UNAVAILABLE/DEADLINE_EXCEEDED with backoff — writes are atomic so retrying is safe.
Example fix
// before
source.UpdateDocument(ctx, "users/u999", nil, map[string]any{"age": 30}) // Update path, doc missing
// after
source.UpdateDocument(ctx, "users/u999", map[string]any{"age": 30}, nil) // Set + MergeAll upserts Defensive patterns
Strategy: validation
Validate before calling
// Go
func validateUpdateTarget(client *firestore.Client, docPath string, updates map[string]any) error {
if docPath == "" {
return errors.New("document path is required")
}
for f := range updates {
if f == "" || strings.HasPrefix(f, ".") || strings.HasSuffix(f, ".") || strings.Contains(f, "..") {
return fmt.Errorf("invalid field path %q", f)
}
}
if _, err := client.Doc(docPath).Get(context.Background()); status.Code(err) == codes.NotFound && len(updates) > 0 {
return fmt.Errorf("document %q does not exist; Update() requires it, use Set path", docPath)
}
return nil
} Type guard
func isValidFieldPath(f string) bool {
return f != "" && !strings.HasPrefix(f, ".") && !strings.HasSuffix(f, ".") && !strings.Contains(f, "..")
} Try / catch
resp, err := source.UpdateDocument(ctx, docPath, updates, nil)
if err != nil {
if strings.Contains(err.Error(), "No document to update") {
resp, err = source.UpdateDocument(ctx, docPath, nil, data)
}
if err != nil {
return fmt.Errorf("update failed: %w", err)
}
} Prevention
- Use the Set/MergeAll path when the document may not exist; reserve Update for existing docs.
- Sanitize field paths (no empty/dotted segments) before updating.
- Keep documents under 1 MiB.
- Retry UNAVAILABLE/DEADLINE_EXCEEDED — updates are atomic and idempotent to re-apply.
When it happens
Trigger: Calling UpdateDocument on a non-existent document path via the Update path (fails with NotFound), payload exceeding 1 MiB, no write permission, or an invalid field path in updates (empty string, leading/trailing dots, '..').
Common situations: Updating a non-existent document with 'updates' mode (must use Set for upsert semantics), rotated service account lacking write IAM, invalid field-path strings like '.name' or 'a..b', transient gRPC outages or quota exhaustion.
Related errors
- failed to update instance: %w
- failed to execute query: %w
- failed to get documents: %w
- failed to add document: %w
- failed to retrieve updated document: %w
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/ad789468729867b5.
Report an issue: GitHub.