microg/GmsCore · error · IllegalStateException
DataPoint already built
Error message
DataPoint already built
What it means
DataPoint.Builder.build() guards against reusing the same Builder after the DataPoint has already been produced. Once build() succeeds, the Builder's built flag is set and any further call to build() throws this IllegalStateException. Builders are single-use by design so the returned DataPoint cannot be mutated unexpectedly afterward.
Source
Thrown at play-services-fitness/src/main/java/com/google/android/gms/fitness/data/DataPoint.java:261
}
/**
* Builder for {@link DataPoint} instances.
*/
public static class Builder {
private final DataPoint dataPoint;
private boolean built = false;
Builder(DataSource dataSource) {
this.dataPoint = DataPoint.create(dataSource);
}
/**
* Builds and returns the {@link DataPoint}.
*/
@NonNull
public DataPoint build() {
if (built) throw new IllegalStateException("DataPoint already built");
this.built = true;
return this.dataPoint;
}
/**
* Sets the value of an activity field to {@code activity}.
*
* @throws IllegalArgumentException If the given index is out of the range for this data type.
* @throws IllegalStateException If the field isn't of format {@link com.google.android.gms.fitness.data.Field#FORMAT_INT32}.
*/
@NonNull
public Builder setActivityField(@NonNull com.google.android.gms.fitness.data.Field field, @NonNull String activity) {
if (built) throw new IllegalStateException("DataPoint already built");
this.dataPoint.getValue(field).setActivity(activity);
return this;
}
/**View on GitHub (pinned to 157c9d86ac)
Solutions
- Create a new DataPoint.Builder for each DataPoint you need instead of reusing one Builder.
- Call build() exactly once, at the end of configuration, and store the returned DataPoint.
- If you need many similar points, wrap construction in a helper method that builds a fresh Builder per call.
Example fix
// before
DataPoint.Builder b = DataPoint.builder(ds).setIntValues(1);
points.add(b.build());
points.add(b.build()); // IllegalStateException
// after
for (int v : vals) {
points.add(DataPoint.builder(ds).setIntValues(v).build());
} Defensive patterns
Strategy: try-catch
Validate before calling
if (builder == null || alreadyBuilt) {
builder = DataPoint.builder(dataSource); // fresh Builder instead of reuse
} Type guard
boolean isUsable(DataPoint.Builder b, Set<DataPoint.Builder> used) { return !used.contains(b); } Try / catch
try {
return builder.build();
} catch (IllegalStateException e) {
// Builder already consumed: create a new Builder and configure it again
builder = DataPoint.builder(dataSource);
return builder.setFloatValues(values).build();
} Prevention
- Treat DataPoint.Builder as strictly single-use: build exactly once, at the end of configuration.
- Create Builders inside the loop/scope that emits each data point; never store them in fields for reuse.
- Write a helper method like newDataPoint(dataSource, values...) so reuse mistakes cannot happen.
When it happens
Trigger: Calling build() twice on the same DataPoint.Builder instance, e.g. inside a loop where the Builder is hoisted outside the loop, or in code paths where build() can be reached twice (retry logic, conditional branches).
Common situations: A Builder stored in a field or closure and reused to emit multiple data points for a DataSet; accidentally calling build() both to validate and to produce the final object; helper methods that take a Builder and call build() at the end while the caller also calls build().
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- The number of values does not match the number of fields
- DataSet has already been built.
- Only one extension per type may be added
- Cannot add twice the same OnSwitchChangeListener
- Cannot remove OnSwitchChangeListener
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/bd369515f61b5585.
Report an issue: GitHub.