What happens
NewSpiceClient() builds a client whose Flight address is the local default and whose HTTP address is the Cloud default:
// client.go
func NewSpiceClient() *SpiceClient {
return NewSpiceClientWithAddress(defaultLocalConfig.FlightUrl) // grpc://127.0.0.1:50051
}
func NewSpiceClientWithAddress(flightAddress string) *SpiceClient {
spiceClient := &SpiceClient{
flightAddress: flightAddress,
baseHttpUrl: defaultCloudConfig.HttpUrl, // https://data.spiceai.io
...
So a client left on its defaults submits SQL over Flight to the local runtime while every HTTP-backed call addresses Spice Cloud. The two halves of one client describe two different runtimes.
Which calls this affects
Every method built on baseHttpUrl:
| method |
route |
IsRuntimeHealthy |
/health |
IsRuntimeReady |
/v1/ready |
GetRuntimeStatus |
/v1/status |
RefreshDataset |
/v1/datasets/{name}/acceleration/refresh |
Search |
/v1/search |
ListActiveQueries / CancelActiveQuery |
/v1/sql/active, /v1/sql/{id}/cancel |
The listing and cancellation pair makes it most visible, because those two are useless against the wrong runtime: a query submitted over local Flight is never listed, and its id cannot be cancelled. But the health and readiness probes have the same shape — a default client reports on Cloud's health, not on the runtime it is querying.
Why this is not a small fix
Making the defaults a pair changes where already-shipped calls go. Anyone relying on NewSpiceClient() + WithApiKey() reaching Cloud over HTTP (without WithSpiceCloudAddress()) would silently start addressing 127.0.0.1:8090. It needs a deliberate decision about the default and, most likely, a release note — which is why it is filed rather than folded into an SDK feature PR.
Options
NewSpiceClient() takes both local defaults, and WithSpiceCloudAddress() sets both Cloud defaults. Consistent, but changes existing HTTP behavior.
- Derive the HTTP default from the Flight address whenever the caller supplied one, keeping the current default only for the no-argument Cloud path.
- Keep the current defaults and require
WithHttpAddress for local HTTP, documenting the split at each method.
Option 3 is what the docs say today (see #80, which documents the split on the two active-query methods); 1 or 2 would remove the trap instead of describing it.
Found by Copilot's review on #80.
What happens
NewSpiceClient()builds a client whose Flight address is the local default and whose HTTP address is the Cloud default:So a client left on its defaults submits SQL over Flight to the local runtime while every HTTP-backed call addresses Spice Cloud. The two halves of one client describe two different runtimes.
Which calls this affects
Every method built on
baseHttpUrl:IsRuntimeHealthy/healthIsRuntimeReady/v1/readyGetRuntimeStatus/v1/statusRefreshDataset/v1/datasets/{name}/acceleration/refreshSearch/v1/searchListActiveQueries/CancelActiveQuery/v1/sql/active,/v1/sql/{id}/cancelThe listing and cancellation pair makes it most visible, because those two are useless against the wrong runtime: a query submitted over local Flight is never listed, and its id cannot be cancelled. But the health and readiness probes have the same shape — a default client reports on Cloud's health, not on the runtime it is querying.
Why this is not a small fix
Making the defaults a pair changes where already-shipped calls go. Anyone relying on
NewSpiceClient()+WithApiKey()reaching Cloud over HTTP (withoutWithSpiceCloudAddress()) would silently start addressing127.0.0.1:8090. It needs a deliberate decision about the default and, most likely, a release note — which is why it is filed rather than folded into an SDK feature PR.Options
NewSpiceClient()takes both local defaults, andWithSpiceCloudAddress()sets both Cloud defaults. Consistent, but changes existing HTTP behavior.WithHttpAddressfor local HTTP, documenting the split at each method.Option 3 is what the docs say today (see #80, which documents the split on the two active-query methods); 1 or 2 would remove the trap instead of describing it.
Found by Copilot's review on #80.