Skip to content

feat: register custom ComputeLroErrorParser for Compute LROs - #14065

Draft
nnicolee wants to merge 2 commits into
feat/lro-generic-error-propagationfrom
feat/lro-compute-poc2
Draft

feat: register custom ComputeLroErrorParser for Compute LROs#14065
nnicolee wants to merge 2 commits into
feat/lro-generic-error-propagationfrom
feat/lro-compute-poc2

Conversation

@nnicolee

@nnicolee nnicolee commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Overview

This is POC 2 that implements Phase 2 of Compute Engine's custom REST LRO error details propagation.

Instead of generating the parser class via code generation (which was the approach in POC 1), this POC introduces a manually written, package-private parser class in the Compute stub module and configures the code generator to register this parser during stub initialization. The parser class is protected from being wiped out during future Librarian code regeneration.

Key Changes

  1. Handwritten Parser Class: Added a package-private parser implementation ComputeLroErrorParser.java inside the java-compute stub package. It extracts nested Compute LRO errors from Operation payloads and translates them into standard ErrorDetails (utilizing ErrorInfo).
  2. Librarian Config: Updated librarian.yaml to include ComputeLroErrorParser.java in the keep block. This prevents the Librarian regeneration tool from deleting or overwriting the manual parser file.
  3. Generator Settings Registration: Modified RetrySettingsComposer.java to automatically generate the registration of new ComputeLroErrorParser() inside the generated Compute stub settings (like AddressesStubSettings.java, NodeTemplatesStubSettings.java, etc.).
  4. Integration Test Safety: Explicitly excluded the test package com.google.cloud.compute.v1small from parser registration inside RetrySettingsComposer.java. This keeps the integration test goldens untouched and ensures the test suite compiles and passes cleanly without requiring a mock parser.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a custom LRO error parser (ComputeLroErrorParser) for the Google Cloud Compute Java client and updates the GAPIC generator (RetrySettingsComposer) to conditionally instantiate and pass this parser when generating LRO settings for com.google.cloud.compute.v1 services. The reviewer provided feedback on ComputeLroErrorParser to improve robustness: first, by conditionally adding message and location to the ErrorInfo metadata map only when they are non-empty; and second, by handling cases where code or message might be empty to prevent poorly formatted error messages (e.g., : message or code: ).

Comment on lines +41 to +51
List<Any> rawErrorMessages = new ArrayList<>();
for (Errors error : operation.getError().getErrorsList()) {
ErrorInfo errorInfo =
ErrorInfo.newBuilder()
.setReason(error.getCode())
.setDomain("googleapis.com")
.putMetadata("message", error.getMessage())
.putMetadata("location", error.getLocation())
.build();
rawErrorMessages.add(Any.pack(errorInfo));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Avoid adding empty strings to the ErrorInfo metadata map if message or location are not populated. We can conditionally add them only when they are non-empty to keep the metadata clean.

    List<Any> rawErrorMessages = new ArrayList<>();
    for (Errors error : operation.getError().getErrorsList()) {
      ErrorInfo.Builder errorInfoBuilder =
          ErrorInfo.newBuilder()
              .setReason(error.getCode())
              .setDomain("googleapis.com");
      if (!error.getMessage().isEmpty()) {
        errorInfoBuilder.putMetadata("message", error.getMessage());
      }
      if (!error.getLocation().isEmpty()) {
        errorInfoBuilder.putMetadata("location", error.getLocation());
      }
      rawErrorMessages.add(Any.pack(errorInfoBuilder.build()));
    }

Comment on lines +64 to +71
StringBuilder sb = new StringBuilder();
for (Errors error : operation.getError().getErrorsList()) {
if (sb.length() > 0) {
sb.append("; ");
}
sb.append(error.getCode()).append(": ").append(error.getMessage());
}
return sb.toString();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

If either code or message is empty, appending them directly with : results in poorly formatted error messages like : message or code: . It is better to conditionally format the string based on which fields are present.

    StringBuilder sb = new StringBuilder();
    for (Errors error : operation.getError().getErrorsList()) {
      String code = error.getCode();
      String message = error.getMessage();
      if (code.isEmpty() && message.isEmpty()) {
        continue;
      }
      if (sb.length() > 0) {
        sb.append("; ");
      }
      if (!code.isEmpty() && !message.isEmpty()) {
        sb.append(code).append(": ").append(message);
      } else if (!code.isEmpty()) {
        sb.append(code);
      } else {
        sb.append(message);
      }
    }
    return sb.toString();

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed for 'gapic-generator-java-root'

Failed conditions
26.1% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed for 'gapic-generator-java-root'

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

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