{"record":{"id":"c4950a90cbec8644","repo":"grpc/grpc-java","slug":"error-occurred-in-response-from-s2a-error-code","errorCode":null,"errorMessage":"Error occurred in response from S2A, error code: %d, error message: \"%s\".","messagePattern":"Error occurred in response from S2A, error code: (.+?), error message: \"(.+?)\"\\.","errorType":"exception","errorClass":"S2AConnectionException","httpStatus":null,"severity":"error","filePath":"s2a/src/main/java/io/grpc/s2a/internal/handshaker/S2APrivateKeyMethod.java","lineNumber":132,"sourceCode":"      throws IOException, InterruptedException {\n    checkArgument(input.length > 0, \"No bytes to sign.\");\n    SignatureAlgorithm s2aSignatureAlgorithm =\n        convertOpenSslSignAlgToS2ASignAlg(signatureAlgorithm);\n    SessionReq.Builder reqBuilder =\n        SessionReq.newBuilder()\n            .setOffloadPrivateKeyOperationReq(\n                OffloadPrivateKeyOperationReq.newBuilder()\n                    .setOperation(OffloadPrivateKeyOperationReq.PrivateKeyOperation.SIGN)\n                    .setSignatureAlgorithm(s2aSignatureAlgorithm)\n                    .setRawBytes(ByteString.copyFrom(input)));\n    if (localIdentity.isPresent()) {\n      reqBuilder.setLocalIdentity(localIdentity.get().getIdentity());\n    }\n\n    SessionResp resp = stub.send(reqBuilder.build());\n\n    if (resp.hasStatus() && resp.getStatus().getCode() != 0) {\n      throw new S2AConnectionException(\n          String.format(\n              \"Error occurred in response from S2A, error code: %d, error message: \\\"%s\\\".\",\n              resp.getStatus().getCode(), resp.getStatus().getDetails()));\n    }\n    if (!resp.hasOffloadPrivateKeyOperationResp()) {\n      throw new S2AConnectionException(\"No valid response received from S2A.\");\n    }\n    return resp.getOffloadPrivateKeyOperationResp().getOutBytes().toByteArray();\n  }\n\n  @Override\n  public byte[] decrypt(SSLEngine engine, byte[] input) {\n    throw new UnsupportedOperationException(\"decrypt is not supported.\");\n  }\n}","sourceCodeStart":114,"sourceCodeEnd":147,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/s2a/src/main/java/io/grpc/s2a/internal/handshaker/S2APrivateKeyMethod.java#L114-L147","documentation":"S2APrivateKeyMethod.sign sends a SessionReq to the S2A offload service and checks the returned SessionResp status. If S2A reports a non-zero status code, it throws S2AConnectionException carrying the S2A error code and details — meaning the offload request failed on the S2A side rather than in the local TLS stack.","triggerScenarios":"Calling sign(engine, bytes) during an S2A-offloaded handshake when resp.hasStatus() is true and status code != 0 — e.g. S2A cannot access the private key, the identity (localIdentity) is wrong or not provisioned, the handshake context is stale, or the S2A service rejected the request.","commonSituations":"S2A deployment lacks the certificate/key referenced by the local identity; workload identity mismatch (wrong SPIFFE ID in s2a config); S2A and application version skew; transient S2A backend errors surfaced with a specific code.","solutions":["Read the error code and details in the exception message and look them up in the S2A handshaker status documentation to identify the server-side failure.","Verify the local identity configured for the channel matches a certificate/key actually provisioned in S2A (SPIFFE ID, cert chain).","Check S2A service logs around the failure for the corresponding request; confirm the target S2A instance is healthy.","Add retry/backoff for transient codes and fail fast (alert) on persistent identity/key errors."],"exampleFix":"// before\nbyte[] sig = keyMethod.sign(engine, input); // throws on any S2A error\n// after\ntry {\n  byte[] sig = keyMethod.sign(engine, input);\n} catch (S2AConnectionException e) {\n  if (isTransient(e)) retry(); else failHandshake(e);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  byte[] sig = keyMethod.sign(engine, input);\n} catch (S2AConnectionException e) {\n  if (isTransientCode(e)) {\n    retryWithBackoff();\n  } else {\n    alertAndFailHandshake(e); // persistent identity/key problem\n  }\n}","preventionTips":["Provision and verify S2A identities/keys before enabling offload for a workload.","Monitor S2A status codes and alert on persistent non-zero codes.","Keep S2A service and client versions compatible.","Classify error codes: retry transient ones, fail fast on identity/config errors."],"tags":["grpc","s2a","tls","remote-service-error"],"backgroundTag":"upstream-api-error","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}