Skip to content

Fix IndexConnection.UpsertRecords swallowing errors#139

Merged
austin-denoble merged 7 commits intomainfrom
adenoble/fix-upsert-records-error-swallowing
Mar 4, 2026
Merged

Fix IndexConnection.UpsertRecords swallowing errors#139
austin-denoble merged 7 commits intomainfrom
adenoble/fix-upsert-records-error-swallowing

Conversation

@austin-denoble
Copy link
Copy Markdown
Contributor

@austin-denoble austin-denoble commented Mar 4, 2026

Problem

The IndexConnection.UpsertRecords method is currently swallowing errors. For example, if you're trying to call UpsertRecords on a non-integrated index, the resulting 400 error is swallowed, and never surfaced to the user.

Solution

  • Make sure we're not swallowing errors on the IndexConnection.UpsertRecords method, check res.StatusCode directly to validate upsert response.
  • Fix broken integration test that should have been failing the whole time.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update
  • Infrastructure change (CI configs, etc)
  • Non-code change (docs, etc)
  • None of the above: (explain here)

Test Plan

CI - unit & integration testing

The integration test that began failing with this error after making this change validates the approach. Previously, this test was running UpsertRecords against a non-integrated index, and failing silently with a successful test:

=== RUN   TestRunSuites/TestIntegratedInference#01
    index_connection_test.go:597: 
        	Error Trace:	/home/runner/work/go-pinecone/go-pinecone/pinecone/index_connection_test.go:597
        	Error:      	Received unexpected error:
        	            	{"status_code":400,"body":"{\"error\":{\"code\":\"INVALID_ARGUMENT\",\"message\":\"Integrated inference is not configured for this index\"},\"status\":400}","error_code":"INVALID_ARGUMENT","message":"failed to upsert records: Integrated inference is not configured for this index"}
        	Test:       	TestRunSuites/TestIntegratedInference#01

I've also built go-pinecone locally and validated the behavior running UpsertRecords against an integrated and non-integrated index.

UpsertRecords against a non-integrated index

Before

Invalid upsert against a non-integrated index

go run main.go --indexName test-overload --upsertRecords
API Key: <REDACTED>
Upserted 100 records (1 of 2 batches)
Upserted 100 records (2 of 2 batches)
Upserted 200 records to namespaces [test-namespace]

After

Invalid upsert against a non-integrated index

go run main.go --indexName test-overload --upsertRecords
API Key: <REDACTED>
panic: {"status_code":400,"body":"{\"error\":{\"code\":\"INVALID_ARGUMENT\",\"message\":\"Integrated inference is not configured for this index\"},\"status\":400}","error_code":"INVALID_ARGUMENT","message":"failed to upsert records: Integrated inference is not configured for this index"}

goroutine 1 [running]:
main.upsertNumberOfRecordsToNewIndex(0xc8, {0x16d5df2f6, 0xd})
	/Users/austin/workspace/go-pinecone-consumer/main.go:1059 +0x5d4
main.main()
	/Users/austin/workspace/go-pinecone-consumer/main.go:143 +0x2d4
exit status 2

Valid upsert against an integrated index (res.StatusCode == http.StatusCreated)

go run main.go --indexName test-integrated --upsertRecords
API Key: <REDACTED>
Upserted 95 records (1 of 3 batches)
Upserted 95 records (2 of 3 batches)
Upserted 10 records (3 of 3 batches)
Upserted 200 records to namespaces [test-namespace]

The error'ing is the correct behavior here, and we properly surface the API errors when the status isn't successful.


Note

Medium Risk
Behavior changes in UpsertRecords (and some other data-plane calls) now correctly return errors for non-success HTTP responses, which may break consumers that previously relied on silent success; scope is otherwise small and well-targeted.

Overview
Fixes IndexConnection.UpsertRecords to stop swallowing server-side failures by checking the HTTP status (201 Created) and returning handleErrorResponseBody(...) when the API responds with an error; the upsert request error is also wrapped with %w.

Improves HTTP resource/error handling across related calls by adding missing defer ...Body.Close() and explicit non-200 status checks (notably SearchRecords, DescribeImport, ListImports, Client.ListBackups, and AdminClient.APIKey.List).

Updates the integrated inference integration test to wait for index readiness before data-plane calls and to create/close an IndexConnection from the newly created index host, ensuring failures are actually surfaced.

Written by Cursor Bugbot for commit 1ee2602. This will update automatically on new commits. Configure here.

…or 201 not 200. update TestIntegratedInference integration test to properly target the integrated index for upsert rather than the shared serverless index - errors were being swallowed silently before on this
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: New IndexConnection never closed, leaking gRPC connection
    • Added a deferred idxConn.Close() (guarded by a nil check) in TestIntegratedInference so the gRPC connection created by Client.Index is always released.

Create PR

Or push these changes by commenting:

@cursor push 1608f65801
Preview (1608f65801)
diff --git a/pinecone/index_connection_test.go b/pinecone/index_connection_test.go
--- a/pinecone/index_connection_test.go
+++ b/pinecone/index_connection_test.go
@@ -597,6 +597,11 @@
 	idxConn, err := ts.client.Index(NewIndexConnParams{Host: index.Host, Namespace: ts.namespaces[0]})
 	assert.NoError(ts.T(), err)
 	assert.NotNil(ts.T(), idxConn)
+	if idxConn != nil {
+		defer func() {
+			assert.NoError(ts.T(), idxConn.Close())
+		}()
+	}
 
 	err = idxConn.UpsertRecords(ctx, records)
 	assert.NoError(ts.T(), err)
This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

… remove MatchTerms from integration test since we're not using the appropriate model to call it here
if err != nil {
return nil, err
}
defer res.Body.Close()
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were missing closing the response body properly in a few places, so I cleaned that up.

}
defer res.Body.Close()

if res.StatusCode != http.StatusCreated {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the source of the original bug involving UpsertRecords swallowing server errors completely.

}
defer res.Body.Close()

if res.StatusCode != http.StatusOK {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SearchRecords, DescribeImport, and ListImports were also missing proper evaluation of the res.StatusCode so that's now been filled in.

These should all be 200s, you can the implementation in pinecone-db here:

In both cases we return Ok(Response::new(...)), which should default to 200 in tonic.

@austin-denoble austin-denoble merged commit 388e4d7 into main Mar 4, 2026
6 checks passed
@austin-denoble austin-denoble deleted the adenoble/fix-upsert-records-error-swallowing branch March 4, 2026 22:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant