[object Object]

← back to Cli Printing Press

fix(cli): detect partial-failure response shape in :mutate handlers, add --allow-partial-failure flag (#1360)

875d64e9c238f937223ae8eadb6ba0f76c20d0a3 · 2026-05-17 01:54:35 -0400 · tallyberner

* fix(cli): detect partial-failure response shape in mutate handlers

Add --allow-partial-failure flag. Mutate envelope's success now depends
on both HTTP status and absence of body-level partial-failure (e.g.
Google Ads partialFailureError). Generic detector lives in helpers.go,
not coupled to one API: any 2xx body with a top-level
partialFailureError carrying a non-zero code or non-empty message is
flagged, results[].resourceName is extracted, and the typed exit
(code 6, distinct from apiErr's code 5) fires unless
--allow-partial-failure downgrades it to a stderr warning.

Detection runs once per mutate call before output-mode selection so
table, JSON envelope, --quiet, and raw paths all surface the same
exit code. partialFailureReport is emitted into the envelope under
partial_failure with field/message/code/details/resource_names so
agents can route per-operation remediation.

Runtime test in generator_test.go drops a *_test.go into a generated
Petstore CLI module and runs go test against the emitted
detectPartialFailure; this is the load-bearing safeguard that proves
the detector works on a Google-Ads-shaped body, not just that the
strings are emitted.

* fix(cli): enforce partial-failure exit on mutate raw/quiet output path

Codex review flagged a gap: when neither the wantsHumanTable nor the
asJSON/piped branch handled a mutate response, control fell through to
printOutputWithFlags without checking partialFailure. That meant
--quiet, --csv, --plain, and default terminal raw output would exit 0
on a detected partial failure even though the warning was printed to
stderr — same silent-swallow regression the patch is supposed to be
preventing for JSON consumers.

Wrap the fall-through call so the typed code-6 exit fires unless
--allow-partial-failure is set, matching the table and JSON paths.

* test(cli): update golden fixtures for partial-failure detection

Updated 18 golden cases to reflect the new emitted code:
  - helpers.go gains detectPartialFailure + partialFailureErr +
    partialFailureReport.
  - root.go gains the --allow-partial-failure persistent flag and the
    rootFlags.allowPartialFailure field.
  - mutate command handlers (POST/PUT/PATCH/DELETE) gain the detection
    block at the top of the response handling, partialFailure-aware
    envelope serialization, and the fall-through partial-failure exit
    guard so --quiet/--csv/--plain/raw output paths surface code 6 too.

Behaviour change is intentional and matches the patch in the prior two
commits.

* fix(cli): include allowPartialFailure in JSON envelope success

When --allow-partial-failure is set and a partial failure is detected, the
process exits 0 (the user opted in to allow it) but the JSON envelope was
still emitting success: false. Automated callers parsing the envelope to
decide whether to retry or alert would see a failure signal on an
intentionally-allowed partial result, disagreeing with the exit code.

Align the envelope's success expression with the exit-code semantics:
treat the request as successful when the status is 2xx AND there is no
partial failure OR the caller passed --allow-partial-failure. Regenerated
goldens mirror the template fix in every affected case.

---------

Co-authored-by: dior <agents@futureremodeling.com>
Co-authored-by: Trevin Chow <trevin@trevinchow.com>

Files touched

Diff

commit 875d64e9c238f937223ae8eadb6ba0f76c20d0a3
Author: tallyberner <127001603+tallyberner@users.noreply.github.com>
Date:   Sun May 17 01:54:35 2026 -0400

    fix(cli): detect partial-failure response shape in :mutate handlers, add --allow-partial-failure flag (#1360)
    
    * fix(cli): detect partial-failure response shape in mutate handlers
    
    Add --allow-partial-failure flag. Mutate envelope's success now depends
    on both HTTP status and absence of body-level partial-failure (e.g.
    Google Ads partialFailureError). Generic detector lives in helpers.go,
    not coupled to one API: any 2xx body with a top-level
    partialFailureError carrying a non-zero code or non-empty message is
    flagged, results[].resourceName is extracted, and the typed exit
    (code 6, distinct from apiErr's code 5) fires unless
    --allow-partial-failure downgrades it to a stderr warning.
    
    Detection runs once per mutate call before output-mode selection so
    table, JSON envelope, --quiet, and raw paths all surface the same
    exit code. partialFailureReport is emitted into the envelope under
    partial_failure with field/message/code/details/resource_names so
    agents can route per-operation remediation.
    
    Runtime test in generator_test.go drops a *_test.go into a generated
    Petstore CLI module and runs go test against the emitted
    detectPartialFailure; this is the load-bearing safeguard that proves
    the detector works on a Google-Ads-shaped body, not just that the
    strings are emitted.
    
    * fix(cli): enforce partial-failure exit on mutate raw/quiet output path
    
    Codex review flagged a gap: when neither the wantsHumanTable nor the
    asJSON/piped branch handled a mutate response, control fell through to
    printOutputWithFlags without checking partialFailure. That meant
    --quiet, --csv, --plain, and default terminal raw output would exit 0
    on a detected partial failure even though the warning was printed to
    stderr — same silent-swallow regression the patch is supposed to be
    preventing for JSON consumers.
    
    Wrap the fall-through call so the typed code-6 exit fires unless
    --allow-partial-failure is set, matching the table and JSON paths.
    
    * test(cli): update golden fixtures for partial-failure detection
    
    Updated 18 golden cases to reflect the new emitted code:
      - helpers.go gains detectPartialFailure + partialFailureErr +
        partialFailureReport.
      - root.go gains the --allow-partial-failure persistent flag and the
        rootFlags.allowPartialFailure field.
      - mutate command handlers (POST/PUT/PATCH/DELETE) gain the detection
        block at the top of the response handling, partialFailure-aware
        envelope serialization, and the fall-through partial-failure exit
        guard so --quiet/--csv/--plain/raw output paths surface code 6 too.
    
    Behaviour change is intentional and matches the patch in the prior two
    commits.
    
    * fix(cli): include allowPartialFailure in JSON envelope success
    
    When --allow-partial-failure is set and a partial failure is detected, the
    process exits 0 (the user opted in to allow it) but the JSON envelope was
    still emitting success: false. Automated callers parsing the envelope to
    decide whether to retry or alert would see a failure signal on an
    intentionally-allowed partial result, disagreeing with the exit code.
    
    Align the envelope's success expression with the exit-code semantics:
    treat the request as successful when the status is 2xx AND there is no
    partial failure OR the caller passed --allow-partial-failure. Regenerated
    goldens mirror the template fix in every affected case.
    
    ---------
    
    Co-authored-by: dior <agents@futureremodeling.com>
    Co-authored-by: Trevin Chow <trevin@trevinchow.com>
---
 internal/generator/generator_test.go               | 147 ++++++++++++++++++++-
 .../generator/templates/command_endpoint.go.tmpl   |  57 +++++++-
 internal/generator/templates/helpers.go.tmpl       |  75 +++++++++++
 internal/generator/templates/root.go.tmpl          |   6 +
 .../embedded-paged-api/internal/cli/helpers.go     |  75 +++++++++++
 .../internal/cli/helpers.go                        |  75 +++++++++++
 .../expected/generate-golden-api/dogfood.json      |   4 +-
 .../printing-press-golden/internal/cli/helpers.go  |  75 +++++++++++
 .../internal/cli/projects_avatar_upload-project.go |  55 +++++++-
 .../internal/cli/projects_create.go                |  55 +++++++-
 .../internal/cli/projects_tasks_update-project.go  |  55 +++++++-
 .../printing-press-golden/internal/cli/root.go     |  44 +++---
 .../internal/cli/things_get.go                     |  55 +++++++-
 .../internal/cli/things_list.go                    |  55 +++++++-
 .../internal/cli/stores_create.go                  |  55 +++++++-
 15 files changed, 846 insertions(+), 42 deletions(-)

diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go
index e669ef5b..731bfabb 100644
--- a/internal/generator/generator_test.go
+++ b/internal/generator/generator_test.go
@@ -4368,7 +4368,38 @@ func TestGeneratedOutput_MutatingCommandsHaveEnvelope(t *testing.T) {
 	assert.Contains(t, content, `"action":`)
 	assert.Contains(t, content, `"resource":`)
 	assert.Contains(t, content, `"status":   statusCode`)
-	assert.Contains(t, content, `"success":  statusCode >= 200 && statusCode < 300`)
+	// Mutate envelope's success depends on HTTP status AND the absence of a
+	// body-level partial-failure (e.g. Google Ads partialFailureError), unless
+	// the caller opted in via --allow-partial-failure (flags.allowPartialFailure)
+	// in which case the envelope agrees with the exit-code 0.
+	assert.Contains(t, content, `"success":  statusCode >= 200 && statusCode < 300 && (partialFailure == nil || flags.allowPartialFailure)`)
+	// Detection runs before any output-mode branch so the exit code is
+	// consistent across table, JSON envelope, and raw output paths.
+	assert.Contains(t, content, `detectPartialFailure(data)`)
+	// --allow-partial-failure downgrades the typed exit (code 6) to a warning.
+	assert.Contains(t, content, `flags.allowPartialFailure`)
+	assert.Contains(t, content, `partialFailureErr(`)
+
+	// The generated helpers.go must carry the detection helper, the
+	// typed-exit constructor, and the structured report shape. These are
+	// what makes the partial-failure path machine-readable; if any goes
+	// missing on regen the silent-swallow regression returns.
+	helpersGo, err := os.ReadFile(filepath.Join(outputDir, "internal", "cli", "helpers.go"))
+	require.NoError(t, err)
+	helpersContent := string(helpersGo)
+	assert.Contains(t, helpersContent, `func detectPartialFailure(`)
+	assert.Contains(t, helpersContent, `func partialFailureErr(`)
+	assert.Contains(t, helpersContent, `type partialFailureReport struct`)
+	assert.Contains(t, helpersContent, `&cliError{code: 6, err: err}`)
+
+	// Root.go must expose the --allow-partial-failure persistent flag and
+	// the matching rootFlags field.
+	rootGo, err := os.ReadFile(filepath.Join(outputDir, "internal", "cli", "root.go"))
+	require.NoError(t, err)
+	rootContent := string(rootGo)
+	assert.Contains(t, rootContent, `allow-partial-failure`)
+	assert.Contains(t, rootContent, `allowPartialFailure bool`)
+
 	// Envelope fires on --json and on piped output, but explicit format flags
 	// (--csv, --quiet, --plain) opt out of the auto-JSON path so piped agents
 	// that asked for a non-JSON format actually get it.
@@ -4393,6 +4424,120 @@ func TestGeneratedOutput_MutatingCommandsHaveEnvelope(t *testing.T) {
 	assert.Contains(t, content, `envelope["success"] = false`)
 }
 
+// TestGeneratedOutput_PartialFailureDetectionRuntime drops a runtime
+// test into the generated CLI module and executes go test against the
+// emitted detectPartialFailure helper. This is the load-bearing
+// safeguard: the per-string assertions above prove the strings are
+// emitted, but only running the generated code proves the detector
+// actually identifies a Google-Ads-style partialFailureError body,
+// extracts results[].resourceName, and returns nil on a clean 2xx.
+//
+// The fixture mirrors the shape the Google Ads API returns for a
+// `campaigns:mutate` call where partial_failure=true and at least one
+// operation failed.
+func TestGeneratedOutput_PartialFailureDetectionRuntime(t *testing.T) {
+	t.Parallel()
+
+	outputDir := generatePetstore(t)
+
+	// Place the runtime test alongside helpers.go in the generated
+	// internal/cli package so it can call the unexported detector.
+	runtimeTest := `package cli
+
+import (
+	"encoding/json"
+	"testing"
+)
+
+func TestDetectPartialFailure_GoogleAdsBatchShape(t *testing.T) {
+	body := []byte(` + "`" + `{
+		"results": [
+			{"resourceName": "customers/123/campaigns/1"},
+			{"resourceName": "customers/123/campaigns/2"}
+		],
+		"partialFailureError": {
+			"code": 3,
+			"message": "Some operations failed",
+			"details": [
+				{"errors": [{"errorCode": {"campaignError": "DUPLICATE_NAME"}}]}
+			]
+		}
+	}` + "`" + `)
+	got := detectPartialFailure(body)
+	if got == nil {
+		t.Fatalf("expected partialFailureReport, got nil")
+	}
+	if got.Field != "partialFailureError" {
+		t.Errorf("Field = %q, want %q", got.Field, "partialFailureError")
+	}
+	if got.Code != 3 {
+		t.Errorf("Code = %d, want 3", got.Code)
+	}
+	if got.Message != "Some operations failed" {
+		t.Errorf("Message = %q, want %q", got.Message, "Some operations failed")
+	}
+	if len(got.ResourceNames) != 2 {
+		t.Fatalf("ResourceNames length = %d, want 2", len(got.ResourceNames))
+	}
+	if got.ResourceNames[0] != "customers/123/campaigns/1" {
+		t.Errorf("ResourceNames[0] = %q", got.ResourceNames[0])
+	}
+	// Report must round-trip to the envelope shape. Marshalling here
+	// asserts the json tags match what mutate-envelope consumers expect.
+	out, err := json.Marshal(got)
+	if err != nil {
+		t.Fatalf("json.Marshal(report): %v", err)
+	}
+	var roundTrip map[string]any
+	if err := json.Unmarshal(out, &roundTrip); err != nil {
+		t.Fatalf("json.Unmarshal(report): %v", err)
+	}
+	if roundTrip["field"] != "partialFailureError" {
+		t.Errorf("round-trip field = %v", roundTrip["field"])
+	}
+	if rn, _ := roundTrip["resource_names"].([]any); len(rn) != 2 {
+		t.Errorf("round-trip resource_names = %v", roundTrip["resource_names"])
+	}
+}
+
+func TestDetectPartialFailure_CleanResponseReturnsNil(t *testing.T) {
+	body := []byte(` + "`" + `{"results": [{"resourceName": "customers/123/campaigns/1"}]}` + "`" + `)
+	if got := detectPartialFailure(body); got != nil {
+		t.Errorf("expected nil for clean response, got %+v", got)
+	}
+}
+
+func TestDetectPartialFailure_EmptyErrorObjectIgnored(t *testing.T) {
+	// Some servers return an empty partialFailureError{} when
+	// partial_failure mode was not enabled. Empty code + empty message
+	// must not flag a partial failure or callers exit non-zero on
+	// every batch.
+	body := []byte(` + "`" + `{"results": [], "partialFailureError": {}}` + "`" + `)
+	if got := detectPartialFailure(body); got != nil {
+		t.Errorf("expected nil for empty partialFailureError, got %+v", got)
+	}
+}
+
+func TestDetectPartialFailure_PartialFailureErrTypedExitCode(t *testing.T) {
+	// partialFailureErr must wrap with the typed exit code (6) so the
+	// CLI's ExitCode() emits a distinguishable code; HTTP failures use
+	// apiErr (5), so 6 stays reserved for partial-failure semantics.
+	err := partialFailureErr(&jsonSyntaxStub{msg: "x"})
+	if got := ExitCode(err); got != 6 {
+		t.Errorf("ExitCode = %d, want 6", got)
+	}
+}
+
+type jsonSyntaxStub struct{ msg string }
+
+func (e *jsonSyntaxStub) Error() string { return e.msg }
+`
+	testPath := filepath.Join(outputDir, "internal", "cli", "partialfailure_runtime_test.go")
+	require.NoError(t, os.WriteFile(testPath, []byte(runtimeTest), 0o644))
+
+	runGoCommand(t, outputDir, "test", "-run", "TestDetectPartialFailure", "./internal/cli")
+}
+
 // TestCompactListFieldsPreservesUnknownShapes pins the contracts that keep
 // `--agent` / `--compact` from silently emitting {} or partial-strip rows
 // for records that don't match the canonical id/name/title allowlist:
diff --git a/internal/generator/templates/command_endpoint.go.tmpl b/internal/generator/templates/command_endpoint.go.tmpl
index 8ed96435..17ea512b 100644
--- a/internal/generator/templates/command_endpoint.go.tmpl
+++ b/internal/generator/templates/command_endpoint.go.tmpl
@@ -523,6 +523,24 @@ func new{{camel .FuncPrefix}}{{camel .EndpointName}}Cmd(flags *rootFlags) *cobra
 {{- end}}
 
 {{- if not (or (eq .Endpoint.Method "GET") (eq .Endpoint.Method "HEAD"))}}
+			// Inspect the mutate response body for a partial-failure-shaped
+			// field (e.g. Google Ads `partialFailureError`). Several Google
+			// APIs return 200 OK with a partial-failure field when some
+			// operations in the batch failed; ignoring it silently swallows
+			// real failures. Detection runs before output-mode selection so
+			// the exit code is consistent regardless of how stdout is
+			// rendered. --dry-run short-circuits because no real request
+			// was sent.
+			var partialFailure *partialFailureReport
+			if !flags.dryRun && statusCode >= 200 && statusCode < 300 {
+				partialFailure = detectPartialFailure(data)
+				if partialFailure != nil {
+					fmt.Fprintf(os.Stderr, "warning: partial failure detected in %s response: %s\n", "{{.ResourceName}}", partialFailure.Message)
+					if len(partialFailure.ResourceNames) > 0 {
+						fmt.Fprintf(os.Stderr, "         succeeded: %d operation(s)\n", len(partialFailure.ResourceNames))
+					}
+				}
+			}
 			if wantsHumanTable(cmd.OutOrStdout(), flags) {
 				// Check if response contains an array (directly or wrapped in "data")
 				var items []map[string]any
@@ -530,6 +548,9 @@ func new{{camel .FuncPrefix}}{{camel .EndpointName}}Cmd(flags *rootFlags) *cobra
 					if err := printAutoTable(cmd.OutOrStdout(), items); err != nil {
 						fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 					} else {
+						if partialFailure != nil && !flags.allowPartialFailure {
+							return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "{{.ResourceName}}", partialFailure.Message))
+						}
 						return nil
 					}
 				} else {
@@ -538,6 +559,9 @@ func new{{camel .FuncPrefix}}{{camel .EndpointName}}Cmd(flags *rootFlags) *cobra
 						if err := printAutoTable(cmd.OutOrStdout(), wrapped.Data); err != nil {
 							fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 						} else {
+							if partialFailure != nil && !flags.allowPartialFailure {
+								return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "{{.ResourceName}}", partialFailure.Message))
+							}
 							return nil
 						}
 					}
@@ -545,6 +569,9 @@ func new{{camel .FuncPrefix}}{{camel .EndpointName}}Cmd(flags *rootFlags) *cobra
 			}
 			if flags.asJSON || (!isTerminal(cmd.OutOrStdout()) && !flags.csv && !flags.quiet && !flags.plain) {
 				if flags.quiet {
+					if partialFailure != nil && !flags.allowPartialFailure {
+						return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "{{.ResourceName}}", partialFailure.Message))
+					}
 					return nil
 				}
 				// Apply --compact and --select to the API response before wrapping.
@@ -562,7 +589,10 @@ func new{{camel .FuncPrefix}}{{camel .EndpointName}}Cmd(flags *rootFlags) *cobra
 					"resource": "{{.ResourceName}}",
 					"path":     path,
 					"status":   statusCode,
-					"success":  statusCode >= 200 && statusCode < 300,
+					"success":  statusCode >= 200 && statusCode < 300 && (partialFailure == nil || flags.allowPartialFailure),
+				}
+				if partialFailure != nil {
+					envelope["partial_failure"] = partialFailure
 				}
 				if flags.dryRun {
 					envelope["dry_run"] = true
@@ -579,7 +609,13 @@ func new{{camel .FuncPrefix}}{{camel .EndpointName}}Cmd(flags *rootFlags) *cobra
 				if err != nil {
 					return err
 				}
-				return printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true)
+				if perr := printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true); perr != nil {
+					return perr
+				}
+				if partialFailure != nil && !flags.allowPartialFailure {
+					return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "{{.ResourceName}}", partialFailure.Message))
+				}
+				return nil
 			}
 {{- end}}
 {{- if or (eq .Endpoint.Method "GET") (eq .Endpoint.Method "HEAD")}}
@@ -627,7 +663,24 @@ func new{{camel .FuncPrefix}}{{camel .EndpointName}}Cmd(flags *rootFlags) *cobra
 				}
 			}
 {{- end}}
+{{- if not (or (eq .Endpoint.Method "GET") (eq .Endpoint.Method "HEAD"))}}
+			// Fall-through for mutate paths that did not hit the table or
+			// asJSON branches: --quiet, --csv, --plain, and default terminal
+			// raw output. printOutputWithFlags renders the body, then the
+			// typed partial-failure exit fires unless --allow-partial-failure
+			// downgrades it. Without this guard a partial failure would exit
+			// 0 for these output modes — the exact silent-swallow regression
+			// the surrounding patch is preventing for asJSON / piped output.
+			if perr := printOutputWithFlags(cmd.OutOrStdout(), data, flags); perr != nil {
+				return perr
+			}
+			if partialFailure != nil && !flags.allowPartialFailure {
+				return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "{{.ResourceName}}", partialFailure.Message))
+			}
+			return nil
+{{- else}}
 			return printOutputWithFlags(cmd.OutOrStdout(), data, flags)
+{{- end}}
 {{- end}}
 		},
 	}
diff --git a/internal/generator/templates/helpers.go.tmpl b/internal/generator/templates/helpers.go.tmpl
index 8b17ae4c..fbe97902 100644
--- a/internal/generator/templates/helpers.go.tmpl
+++ b/internal/generator/templates/helpers.go.tmpl
@@ -118,6 +118,81 @@ func apiErr(err error) error      { return &cliError{code: 5, err: err} }
 func configErr(err error) error   { return &cliError{code: 10, err: err} }
 func rateLimitErr(err error) error { return &cliError{code: 7, err: err} }
 
+// partialFailureErr signals that the upstream API returned a 2xx with a
+// body shape indicating some operations in a batch failed (e.g. Google
+// Ads `partialFailureError`, similar shapes from Drive batch, Sheets
+// batchUpdate, Cloud Resource Manager). Distinct from apiErr (HTTP-level
+// failure) so callers can distinguish "request rejected" from "request
+// accepted but some ops failed".
+func partialFailureErr(err error) error { return &cliError{code: 6, err: err} }
+
+// partialFailureReport describes the structured detection result for a
+// mutate-style response body. Emitted in the envelope under
+// "partial_failure" so machine-readable callers can route per-operation
+// remediation.
+type partialFailureReport struct {
+	Field         string   `json:"field"`
+	Message       string   `json:"message,omitempty"`
+	Code          int      `json:"code,omitempty"`
+	Details       any      `json:"details,omitempty"`
+	ResourceNames []string `json:"resource_names,omitempty"`
+}
+
+// detectPartialFailure inspects a mutate-style JSON response for a
+// partial-failure-shaped field. Returns nil when no partial failure is
+// detected. The detector is intentionally generic across APIs that emit
+// 2xx-with-batch-errors. New partial-failure-shaped fields are added to
+// partialFailureFields, not at call sites. When `results[]` is present
+// (Google Ads convention) it extracts per-op `resourceName` so callers
+// can see which operations did succeed.
+func detectPartialFailure(data []byte) *partialFailureReport {
+	if len(data) == 0 {
+		return nil
+	}
+	var top map[string]any
+	if err := json.Unmarshal(data, &top); err != nil {
+		return nil
+	}
+	partialFailureFields := []string{"partialFailureError"}
+	for _, field := range partialFailureFields {
+		raw, ok := top[field]
+		if !ok || raw == nil {
+			continue
+		}
+		obj, ok := raw.(map[string]any)
+		if !ok {
+			continue
+		}
+		message, _ := obj["message"].(string)
+		var code int
+		if n, ok := obj["code"].(float64); ok {
+			code = int(n)
+		}
+		// Empty object means partial-failure mode was off or no ops
+		// failed; do not flag.
+		if code == 0 && strings.TrimSpace(message) == "" {
+			continue
+		}
+		report := &partialFailureReport{
+			Field:   field,
+			Message: message,
+			Code:    code,
+			Details: obj["details"],
+		}
+		if results, ok := top["results"].([]any); ok {
+			for _, r := range results {
+				if rm, ok := r.(map[string]any); ok {
+					if name, ok := rm["resourceName"].(string); ok && name != "" {
+						report.ResourceNames = append(report.ResourceNames, name)
+					}
+				}
+			}
+		}
+		return report
+	}
+	return nil
+}
+
 // dryRunOK reports whether the command should short-circuit without doing any
 // real work because --dry-run was set. The verify pipeline probes hand-written
 // commands with --dry-run; commands that put validation in cobra's `Args:` or
diff --git a/internal/generator/templates/root.go.tmpl b/internal/generator/templates/root.go.tmpl
index 4c69d04e..97088e9b 100644
--- a/internal/generator/templates/root.go.tmpl
+++ b/internal/generator/templates/root.go.tmpl
@@ -34,6 +34,11 @@ type rootFlags struct {
 {{- end}}
 	yes          bool
 	agent        bool
+	// allowPartialFailure downgrades a detected response-body partial-failure
+	// (e.g. Google Ads `partialFailureError`) from a non-zero exit to a
+	// stderr warning. Default false so silent partial successes surface as
+	// failures by default.
+	allowPartialFailure bool
 	selectFields string
 	configPath   string
 	profileName  string
@@ -216,6 +221,7 @@ Run '{{.Name}}-pp-cli doctor' to verify auth and connectivity.{{backtick}},
 	rootCmd.PersistentFlags().BoolVar(&noColor, "no-color", false, "Disable colored output")
 	rootCmd.PersistentFlags().BoolVar(&humanFriendly, "human-friendly", false, "Enable colored output and rich formatting")
 	rootCmd.PersistentFlags().BoolVar(&flags.agent, "agent", false, "Set all agent-friendly defaults (--json --compact --no-input --no-color --yes)")
+	rootCmd.PersistentFlags().BoolVar(&flags.allowPartialFailure, "allow-partial-failure", false, "Downgrade response-body partial-failure (e.g. partialFailureError) to a warning instead of a non-zero exit")
 	rootCmd.PersistentFlags().StringVar(&flags.dataSource, "data-source", "auto", "Data source for read commands: auto (live with local fallback), live (API only), local (synced data only)")
 	rootCmd.PersistentFlags().StringVar(&flags.profileName, "profile", "", "Apply values from a saved profile (see '{{.Name}}-pp-cli profile list')")
 	rootCmd.PersistentFlags().StringVar(&flags.deliverSpec, "deliver", "", "Route output to a sink: stdout (default), file:<path>, webhook:<url>")
diff --git a/testdata/golden/expected/generate-embedded-paged-api/embedded-paged-api/internal/cli/helpers.go b/testdata/golden/expected/generate-embedded-paged-api/embedded-paged-api/internal/cli/helpers.go
index 5182dbc1..e7a4de48 100644
--- a/testdata/golden/expected/generate-embedded-paged-api/embedded-paged-api/internal/cli/helpers.go
+++ b/testdata/golden/expected/generate-embedded-paged-api/embedded-paged-api/internal/cli/helpers.go
@@ -102,6 +102,81 @@ func apiErr(err error) error       { return &cliError{code: 5, err: err} }
 func configErr(err error) error    { return &cliError{code: 10, err: err} }
 func rateLimitErr(err error) error { return &cliError{code: 7, err: err} }
 
+// partialFailureErr signals that the upstream API returned a 2xx with a
+// body shape indicating some operations in a batch failed (e.g. Google
+// Ads `partialFailureError`, similar shapes from Drive batch, Sheets
+// batchUpdate, Cloud Resource Manager). Distinct from apiErr (HTTP-level
+// failure) so callers can distinguish "request rejected" from "request
+// accepted but some ops failed".
+func partialFailureErr(err error) error { return &cliError{code: 6, err: err} }
+
+// partialFailureReport describes the structured detection result for a
+// mutate-style response body. Emitted in the envelope under
+// "partial_failure" so machine-readable callers can route per-operation
+// remediation.
+type partialFailureReport struct {
+	Field         string   `json:"field"`
+	Message       string   `json:"message,omitempty"`
+	Code          int      `json:"code,omitempty"`
+	Details       any      `json:"details,omitempty"`
+	ResourceNames []string `json:"resource_names,omitempty"`
+}
+
+// detectPartialFailure inspects a mutate-style JSON response for a
+// partial-failure-shaped field. Returns nil when no partial failure is
+// detected. The detector is intentionally generic across APIs that emit
+// 2xx-with-batch-errors. New partial-failure-shaped fields are added to
+// partialFailureFields, not at call sites. When `results[]` is present
+// (Google Ads convention) it extracts per-op `resourceName` so callers
+// can see which operations did succeed.
+func detectPartialFailure(data []byte) *partialFailureReport {
+	if len(data) == 0 {
+		return nil
+	}
+	var top map[string]any
+	if err := json.Unmarshal(data, &top); err != nil {
+		return nil
+	}
+	partialFailureFields := []string{"partialFailureError"}
+	for _, field := range partialFailureFields {
+		raw, ok := top[field]
+		if !ok || raw == nil {
+			continue
+		}
+		obj, ok := raw.(map[string]any)
+		if !ok {
+			continue
+		}
+		message, _ := obj["message"].(string)
+		var code int
+		if n, ok := obj["code"].(float64); ok {
+			code = int(n)
+		}
+		// Empty object means partial-failure mode was off or no ops
+		// failed; do not flag.
+		if code == 0 && strings.TrimSpace(message) == "" {
+			continue
+		}
+		report := &partialFailureReport{
+			Field:   field,
+			Message: message,
+			Code:    code,
+			Details: obj["details"],
+		}
+		if results, ok := top["results"].([]any); ok {
+			for _, r := range results {
+				if rm, ok := r.(map[string]any); ok {
+					if name, ok := rm["resourceName"].(string); ok && name != "" {
+						report.ResourceNames = append(report.ResourceNames, name)
+					}
+				}
+			}
+		}
+		return report
+	}
+	return nil
+}
+
 // dryRunOK reports whether the command should short-circuit without doing any
 // real work because --dry-run was set. The verify pipeline probes hand-written
 // commands with --dry-run; commands that put validation in cobra's `Args:` or
diff --git a/testdata/golden/expected/generate-golden-api-rich-auth/printing-press-rich-auth/internal/cli/helpers.go b/testdata/golden/expected/generate-golden-api-rich-auth/printing-press-rich-auth/internal/cli/helpers.go
index 3d01225d..7ed03438 100644
--- a/testdata/golden/expected/generate-golden-api-rich-auth/printing-press-rich-auth/internal/cli/helpers.go
+++ b/testdata/golden/expected/generate-golden-api-rich-auth/printing-press-rich-auth/internal/cli/helpers.go
@@ -101,6 +101,81 @@ func apiErr(err error) error       { return &cliError{code: 5, err: err} }
 func configErr(err error) error    { return &cliError{code: 10, err: err} }
 func rateLimitErr(err error) error { return &cliError{code: 7, err: err} }
 
+// partialFailureErr signals that the upstream API returned a 2xx with a
+// body shape indicating some operations in a batch failed (e.g. Google
+// Ads `partialFailureError`, similar shapes from Drive batch, Sheets
+// batchUpdate, Cloud Resource Manager). Distinct from apiErr (HTTP-level
+// failure) so callers can distinguish "request rejected" from "request
+// accepted but some ops failed".
+func partialFailureErr(err error) error { return &cliError{code: 6, err: err} }
+
+// partialFailureReport describes the structured detection result for a
+// mutate-style response body. Emitted in the envelope under
+// "partial_failure" so machine-readable callers can route per-operation
+// remediation.
+type partialFailureReport struct {
+	Field         string   `json:"field"`
+	Message       string   `json:"message,omitempty"`
+	Code          int      `json:"code,omitempty"`
+	Details       any      `json:"details,omitempty"`
+	ResourceNames []string `json:"resource_names,omitempty"`
+}
+
+// detectPartialFailure inspects a mutate-style JSON response for a
+// partial-failure-shaped field. Returns nil when no partial failure is
+// detected. The detector is intentionally generic across APIs that emit
+// 2xx-with-batch-errors. New partial-failure-shaped fields are added to
+// partialFailureFields, not at call sites. When `results[]` is present
+// (Google Ads convention) it extracts per-op `resourceName` so callers
+// can see which operations did succeed.
+func detectPartialFailure(data []byte) *partialFailureReport {
+	if len(data) == 0 {
+		return nil
+	}
+	var top map[string]any
+	if err := json.Unmarshal(data, &top); err != nil {
+		return nil
+	}
+	partialFailureFields := []string{"partialFailureError"}
+	for _, field := range partialFailureFields {
+		raw, ok := top[field]
+		if !ok || raw == nil {
+			continue
+		}
+		obj, ok := raw.(map[string]any)
+		if !ok {
+			continue
+		}
+		message, _ := obj["message"].(string)
+		var code int
+		if n, ok := obj["code"].(float64); ok {
+			code = int(n)
+		}
+		// Empty object means partial-failure mode was off or no ops
+		// failed; do not flag.
+		if code == 0 && strings.TrimSpace(message) == "" {
+			continue
+		}
+		report := &partialFailureReport{
+			Field:   field,
+			Message: message,
+			Code:    code,
+			Details: obj["details"],
+		}
+		if results, ok := top["results"].([]any); ok {
+			for _, r := range results {
+				if rm, ok := r.(map[string]any); ok {
+					if name, ok := rm["resourceName"].(string); ok && name != "" {
+						report.ResourceNames = append(report.ResourceNames, name)
+					}
+				}
+			}
+		}
+		return report
+	}
+	return nil
+}
+
 // dryRunOK reports whether the command should short-circuit without doing any
 // real work because --dry-run was set. The verify pipeline probes hand-written
 // commands with --dry-run; commands that put validation in cobra's `Args:` or
diff --git a/testdata/golden/expected/generate-golden-api/dogfood.json b/testdata/golden/expected/generate-golden-api/dogfood.json
index d3c0383b..f0770511 100644
--- a/testdata/golden/expected/generate-golden-api/dogfood.json
+++ b/testdata/golden/expected/generate-golden-api/dogfood.json
@@ -12,11 +12,11 @@
   },
   "dead_flags": {
     "dead": 0,
-    "total": 18
+    "total": 19
   },
   "dead_functions": {
     "dead": 0,
-    "total": 60
+    "total": 62
   },
   "dir": "<ARTIFACT_DIR>/generate-golden-api/printing-press-golden",
   "example_check": {
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/helpers.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/helpers.go
index 6bdf7e9f..489384d3 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/helpers.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/helpers.go
@@ -102,6 +102,81 @@ func apiErr(err error) error       { return &cliError{code: 5, err: err} }
 func configErr(err error) error    { return &cliError{code: 10, err: err} }
 func rateLimitErr(err error) error { return &cliError{code: 7, err: err} }
 
+// partialFailureErr signals that the upstream API returned a 2xx with a
+// body shape indicating some operations in a batch failed (e.g. Google
+// Ads `partialFailureError`, similar shapes from Drive batch, Sheets
+// batchUpdate, Cloud Resource Manager). Distinct from apiErr (HTTP-level
+// failure) so callers can distinguish "request rejected" from "request
+// accepted but some ops failed".
+func partialFailureErr(err error) error { return &cliError{code: 6, err: err} }
+
+// partialFailureReport describes the structured detection result for a
+// mutate-style response body. Emitted in the envelope under
+// "partial_failure" so machine-readable callers can route per-operation
+// remediation.
+type partialFailureReport struct {
+	Field         string   `json:"field"`
+	Message       string   `json:"message,omitempty"`
+	Code          int      `json:"code,omitempty"`
+	Details       any      `json:"details,omitempty"`
+	ResourceNames []string `json:"resource_names,omitempty"`
+}
+
+// detectPartialFailure inspects a mutate-style JSON response for a
+// partial-failure-shaped field. Returns nil when no partial failure is
+// detected. The detector is intentionally generic across APIs that emit
+// 2xx-with-batch-errors. New partial-failure-shaped fields are added to
+// partialFailureFields, not at call sites. When `results[]` is present
+// (Google Ads convention) it extracts per-op `resourceName` so callers
+// can see which operations did succeed.
+func detectPartialFailure(data []byte) *partialFailureReport {
+	if len(data) == 0 {
+		return nil
+	}
+	var top map[string]any
+	if err := json.Unmarshal(data, &top); err != nil {
+		return nil
+	}
+	partialFailureFields := []string{"partialFailureError"}
+	for _, field := range partialFailureFields {
+		raw, ok := top[field]
+		if !ok || raw == nil {
+			continue
+		}
+		obj, ok := raw.(map[string]any)
+		if !ok {
+			continue
+		}
+		message, _ := obj["message"].(string)
+		var code int
+		if n, ok := obj["code"].(float64); ok {
+			code = int(n)
+		}
+		// Empty object means partial-failure mode was off or no ops
+		// failed; do not flag.
+		if code == 0 && strings.TrimSpace(message) == "" {
+			continue
+		}
+		report := &partialFailureReport{
+			Field:   field,
+			Message: message,
+			Code:    code,
+			Details: obj["details"],
+		}
+		if results, ok := top["results"].([]any); ok {
+			for _, r := range results {
+				if rm, ok := r.(map[string]any); ok {
+					if name, ok := rm["resourceName"].(string); ok && name != "" {
+						report.ResourceNames = append(report.ResourceNames, name)
+					}
+				}
+			}
+		}
+		return report
+	}
+	return nil
+}
+
 // dryRunOK reports whether the command should short-circuit without doing any
 // real work because --dry-run was set. The verify pipeline probes hand-written
 // commands with --dry-run; commands that put validation in cobra's `Args:` or
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_avatar_upload-project.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_avatar_upload-project.go
index 3bddcf56..7727b02d 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_avatar_upload-project.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_avatar_upload-project.go
@@ -50,6 +50,24 @@ func newProjectsAvatarUploadProjectCmd(flags *rootFlags) *cobra.Command {
 			if err != nil {
 				return classifyAPIError(err, flags)
 			}
+			// Inspect the mutate response body for a partial-failure-shaped
+			// field (e.g. Google Ads `partialFailureError`). Several Google
+			// APIs return 200 OK with a partial-failure field when some
+			// operations in the batch failed; ignoring it silently swallows
+			// real failures. Detection runs before output-mode selection so
+			// the exit code is consistent regardless of how stdout is
+			// rendered. --dry-run short-circuits because no real request
+			// was sent.
+			var partialFailure *partialFailureReport
+			if !flags.dryRun && statusCode >= 200 && statusCode < 300 {
+				partialFailure = detectPartialFailure(data)
+				if partialFailure != nil {
+					fmt.Fprintf(os.Stderr, "warning: partial failure detected in %s response: %s\n", "avatar", partialFailure.Message)
+					if len(partialFailure.ResourceNames) > 0 {
+						fmt.Fprintf(os.Stderr, "         succeeded: %d operation(s)\n", len(partialFailure.ResourceNames))
+					}
+				}
+			}
 			if wantsHumanTable(cmd.OutOrStdout(), flags) {
 				// Check if response contains an array (directly or wrapped in "data")
 				var items []map[string]any
@@ -57,6 +75,9 @@ func newProjectsAvatarUploadProjectCmd(flags *rootFlags) *cobra.Command {
 					if err := printAutoTable(cmd.OutOrStdout(), items); err != nil {
 						fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 					} else {
+						if partialFailure != nil && !flags.allowPartialFailure {
+							return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "avatar", partialFailure.Message))
+						}
 						return nil
 					}
 				} else {
@@ -67,6 +88,9 @@ func newProjectsAvatarUploadProjectCmd(flags *rootFlags) *cobra.Command {
 						if err := printAutoTable(cmd.OutOrStdout(), wrapped.Data); err != nil {
 							fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 						} else {
+							if partialFailure != nil && !flags.allowPartialFailure {
+								return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "avatar", partialFailure.Message))
+							}
 							return nil
 						}
 					}
@@ -74,6 +98,9 @@ func newProjectsAvatarUploadProjectCmd(flags *rootFlags) *cobra.Command {
 			}
 			if flags.asJSON || (!isTerminal(cmd.OutOrStdout()) && !flags.csv && !flags.quiet && !flags.plain) {
 				if flags.quiet {
+					if partialFailure != nil && !flags.allowPartialFailure {
+						return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "avatar", partialFailure.Message))
+					}
 					return nil
 				}
 				// Apply --compact and --select to the API response before wrapping.
@@ -91,7 +118,10 @@ func newProjectsAvatarUploadProjectCmd(flags *rootFlags) *cobra.Command {
 					"resource": "avatar",
 					"path":     path,
 					"status":   statusCode,
-					"success":  statusCode >= 200 && statusCode < 300,
+					"success":  statusCode >= 200 && statusCode < 300 && (partialFailure == nil || flags.allowPartialFailure),
+				}
+				if partialFailure != nil {
+					envelope["partial_failure"] = partialFailure
 				}
 				if flags.dryRun {
 					envelope["dry_run"] = true
@@ -108,9 +138,28 @@ func newProjectsAvatarUploadProjectCmd(flags *rootFlags) *cobra.Command {
 				if err != nil {
 					return err
 				}
-				return printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true)
+				if perr := printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true); perr != nil {
+					return perr
+				}
+				if partialFailure != nil && !flags.allowPartialFailure {
+					return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "avatar", partialFailure.Message))
+				}
+				return nil
+			}
+			// Fall-through for mutate paths that did not hit the table or
+			// asJSON branches: --quiet, --csv, --plain, and default terminal
+			// raw output. printOutputWithFlags renders the body, then the
+			// typed partial-failure exit fires unless --allow-partial-failure
+			// downgrades it. Without this guard a partial failure would exit
+			// 0 for these output modes — the exact silent-swallow regression
+			// the surrounding patch is preventing for asJSON / piped output.
+			if perr := printOutputWithFlags(cmd.OutOrStdout(), data, flags); perr != nil {
+				return perr
+			}
+			if partialFailure != nil && !flags.allowPartialFailure {
+				return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "avatar", partialFailure.Message))
 			}
-			return printOutputWithFlags(cmd.OutOrStdout(), data, flags)
+			return nil
 		},
 	}
 	cmd.Flags().BoolVar(&flagOverwrite, "overwrite", false, "Overwrite")
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_create.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_create.go
index 4f1e7b79..fd0ca326 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_create.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_create.go
@@ -66,6 +66,24 @@ func newProjectsCreateCmd(flags *rootFlags) *cobra.Command {
 			if err != nil {
 				return classifyAPIError(err, flags)
 			}
+			// Inspect the mutate response body for a partial-failure-shaped
+			// field (e.g. Google Ads `partialFailureError`). Several Google
+			// APIs return 200 OK with a partial-failure field when some
+			// operations in the batch failed; ignoring it silently swallows
+			// real failures. Detection runs before output-mode selection so
+			// the exit code is consistent regardless of how stdout is
+			// rendered. --dry-run short-circuits because no real request
+			// was sent.
+			var partialFailure *partialFailureReport
+			if !flags.dryRun && statusCode >= 200 && statusCode < 300 {
+				partialFailure = detectPartialFailure(data)
+				if partialFailure != nil {
+					fmt.Fprintf(os.Stderr, "warning: partial failure detected in %s response: %s\n", "projects", partialFailure.Message)
+					if len(partialFailure.ResourceNames) > 0 {
+						fmt.Fprintf(os.Stderr, "         succeeded: %d operation(s)\n", len(partialFailure.ResourceNames))
+					}
+				}
+			}
 			if wantsHumanTable(cmd.OutOrStdout(), flags) {
 				// Check if response contains an array (directly or wrapped in "data")
 				var items []map[string]any
@@ -73,6 +91,9 @@ func newProjectsCreateCmd(flags *rootFlags) *cobra.Command {
 					if err := printAutoTable(cmd.OutOrStdout(), items); err != nil {
 						fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 					} else {
+						if partialFailure != nil && !flags.allowPartialFailure {
+							return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "projects", partialFailure.Message))
+						}
 						return nil
 					}
 				} else {
@@ -83,6 +104,9 @@ func newProjectsCreateCmd(flags *rootFlags) *cobra.Command {
 						if err := printAutoTable(cmd.OutOrStdout(), wrapped.Data); err != nil {
 							fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 						} else {
+							if partialFailure != nil && !flags.allowPartialFailure {
+								return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "projects", partialFailure.Message))
+							}
 							return nil
 						}
 					}
@@ -90,6 +114,9 @@ func newProjectsCreateCmd(flags *rootFlags) *cobra.Command {
 			}
 			if flags.asJSON || (!isTerminal(cmd.OutOrStdout()) && !flags.csv && !flags.quiet && !flags.plain) {
 				if flags.quiet {
+					if partialFailure != nil && !flags.allowPartialFailure {
+						return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "projects", partialFailure.Message))
+					}
 					return nil
 				}
 				// Apply --compact and --select to the API response before wrapping.
@@ -107,7 +134,10 @@ func newProjectsCreateCmd(flags *rootFlags) *cobra.Command {
 					"resource": "projects",
 					"path":     path,
 					"status":   statusCode,
-					"success":  statusCode >= 200 && statusCode < 300,
+					"success":  statusCode >= 200 && statusCode < 300 && (partialFailure == nil || flags.allowPartialFailure),
+				}
+				if partialFailure != nil {
+					envelope["partial_failure"] = partialFailure
 				}
 				if flags.dryRun {
 					envelope["dry_run"] = true
@@ -124,9 +154,28 @@ func newProjectsCreateCmd(flags *rootFlags) *cobra.Command {
 				if err != nil {
 					return err
 				}
-				return printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true)
+				if perr := printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true); perr != nil {
+					return perr
+				}
+				if partialFailure != nil && !flags.allowPartialFailure {
+					return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "projects", partialFailure.Message))
+				}
+				return nil
+			}
+			// Fall-through for mutate paths that did not hit the table or
+			// asJSON branches: --quiet, --csv, --plain, and default terminal
+			// raw output. printOutputWithFlags renders the body, then the
+			// typed partial-failure exit fires unless --allow-partial-failure
+			// downgrades it. Without this guard a partial failure would exit
+			// 0 for these output modes — the exact silent-swallow regression
+			// the surrounding patch is preventing for asJSON / piped output.
+			if perr := printOutputWithFlags(cmd.OutOrStdout(), data, flags); perr != nil {
+				return perr
+			}
+			if partialFailure != nil && !flags.allowPartialFailure {
+				return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "projects", partialFailure.Message))
 			}
-			return printOutputWithFlags(cmd.OutOrStdout(), data, flags)
+			return nil
 		},
 	}
 	cmd.Flags().StringVar(&bodyName, "name", "", "Name")
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_tasks_update-project.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_tasks_update-project.go
index 0d5eeb1f..fadac499 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_tasks_update-project.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/projects_tasks_update-project.go
@@ -73,6 +73,24 @@ func newProjectsTasksUpdateProjectCmd(flags *rootFlags) *cobra.Command {
 			if err != nil {
 				return classifyAPIError(err, flags)
 			}
+			// Inspect the mutate response body for a partial-failure-shaped
+			// field (e.g. Google Ads `partialFailureError`). Several Google
+			// APIs return 200 OK with a partial-failure field when some
+			// operations in the batch failed; ignoring it silently swallows
+			// real failures. Detection runs before output-mode selection so
+			// the exit code is consistent regardless of how stdout is
+			// rendered. --dry-run short-circuits because no real request
+			// was sent.
+			var partialFailure *partialFailureReport
+			if !flags.dryRun && statusCode >= 200 && statusCode < 300 {
+				partialFailure = detectPartialFailure(data)
+				if partialFailure != nil {
+					fmt.Fprintf(os.Stderr, "warning: partial failure detected in %s response: %s\n", "tasks", partialFailure.Message)
+					if len(partialFailure.ResourceNames) > 0 {
+						fmt.Fprintf(os.Stderr, "         succeeded: %d operation(s)\n", len(partialFailure.ResourceNames))
+					}
+				}
+			}
 			if wantsHumanTable(cmd.OutOrStdout(), flags) {
 				// Check if response contains an array (directly or wrapped in "data")
 				var items []map[string]any
@@ -80,6 +98,9 @@ func newProjectsTasksUpdateProjectCmd(flags *rootFlags) *cobra.Command {
 					if err := printAutoTable(cmd.OutOrStdout(), items); err != nil {
 						fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 					} else {
+						if partialFailure != nil && !flags.allowPartialFailure {
+							return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "tasks", partialFailure.Message))
+						}
 						return nil
 					}
 				} else {
@@ -90,6 +111,9 @@ func newProjectsTasksUpdateProjectCmd(flags *rootFlags) *cobra.Command {
 						if err := printAutoTable(cmd.OutOrStdout(), wrapped.Data); err != nil {
 							fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 						} else {
+							if partialFailure != nil && !flags.allowPartialFailure {
+								return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "tasks", partialFailure.Message))
+							}
 							return nil
 						}
 					}
@@ -97,6 +121,9 @@ func newProjectsTasksUpdateProjectCmd(flags *rootFlags) *cobra.Command {
 			}
 			if flags.asJSON || (!isTerminal(cmd.OutOrStdout()) && !flags.csv && !flags.quiet && !flags.plain) {
 				if flags.quiet {
+					if partialFailure != nil && !flags.allowPartialFailure {
+						return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "tasks", partialFailure.Message))
+					}
 					return nil
 				}
 				// Apply --compact and --select to the API response before wrapping.
@@ -114,7 +141,10 @@ func newProjectsTasksUpdateProjectCmd(flags *rootFlags) *cobra.Command {
 					"resource": "tasks",
 					"path":     path,
 					"status":   statusCode,
-					"success":  statusCode >= 200 && statusCode < 300,
+					"success":  statusCode >= 200 && statusCode < 300 && (partialFailure == nil || flags.allowPartialFailure),
+				}
+				if partialFailure != nil {
+					envelope["partial_failure"] = partialFailure
 				}
 				if flags.dryRun {
 					envelope["dry_run"] = true
@@ -131,9 +161,28 @@ func newProjectsTasksUpdateProjectCmd(flags *rootFlags) *cobra.Command {
 				if err != nil {
 					return err
 				}
-				return printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true)
+				if perr := printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true); perr != nil {
+					return perr
+				}
+				if partialFailure != nil && !flags.allowPartialFailure {
+					return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "tasks", partialFailure.Message))
+				}
+				return nil
+			}
+			// Fall-through for mutate paths that did not hit the table or
+			// asJSON branches: --quiet, --csv, --plain, and default terminal
+			// raw output. printOutputWithFlags renders the body, then the
+			// typed partial-failure exit fires unless --allow-partial-failure
+			// downgrades it. Without this guard a partial failure would exit
+			// 0 for these output modes — the exact silent-swallow regression
+			// the surrounding patch is preventing for asJSON / piped output.
+			if perr := printOutputWithFlags(cmd.OutOrStdout(), data, flags); perr != nil {
+				return perr
+			}
+			if partialFailure != nil && !flags.allowPartialFailure {
+				return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "tasks", partialFailure.Message))
 			}
-			return printOutputWithFlags(cmd.OutOrStdout(), data, flags)
+			return nil
 		},
 	}
 	cmd.Flags().BoolVar(&flagNotify, "notify", false, "Notify")
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/root.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/root.go
index ca7494e9..1a1af02e 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/root.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/root.go
@@ -20,25 +20,30 @@ import (
 var version = "1.0.0"
 
 type rootFlags struct {
-	asJSON        bool
-	compact       bool
-	csv           bool
-	plain         bool
-	quiet         bool
-	dryRun        bool
-	noCache       bool
-	noInput       bool
-	idempotent    bool
-	yes           bool
-	agent         bool
-	selectFields  string
-	configPath    string
-	profileName   string
-	deliverSpec   string
-	timeout       time.Duration
-	rateLimit     float64
-	dataSource    string
-	freshnessMeta any
+	asJSON     bool
+	compact    bool
+	csv        bool
+	plain      bool
+	quiet      bool
+	dryRun     bool
+	noCache    bool
+	noInput    bool
+	idempotent bool
+	yes        bool
+	agent      bool
+	// allowPartialFailure downgrades a detected response-body partial-failure
+	// (e.g. Google Ads `partialFailureError`) from a non-zero exit to a
+	// stderr warning. Default false so silent partial successes surface as
+	// failures by default.
+	allowPartialFailure bool
+	selectFields        string
+	configPath          string
+	profileName         string
+	deliverSpec         string
+	timeout             time.Duration
+	rateLimit           float64
+	dataSource          string
+	freshnessMeta       any
 
 	// deliverBuf captures command output when --deliver is set to a
 	// non-stdout sink. Flushed to the sink after Execute returns.
@@ -164,6 +169,7 @@ Run 'printing-press-golden-pp-cli doctor' to verify auth and connectivity.`,
 	rootCmd.PersistentFlags().BoolVar(&noColor, "no-color", false, "Disable colored output")
 	rootCmd.PersistentFlags().BoolVar(&humanFriendly, "human-friendly", false, "Enable colored output and rich formatting")
 	rootCmd.PersistentFlags().BoolVar(&flags.agent, "agent", false, "Set all agent-friendly defaults (--json --compact --no-input --no-color --yes)")
+	rootCmd.PersistentFlags().BoolVar(&flags.allowPartialFailure, "allow-partial-failure", false, "Downgrade response-body partial-failure (e.g. partialFailureError) to a warning instead of a non-zero exit")
 	rootCmd.PersistentFlags().StringVar(&flags.dataSource, "data-source", "auto", "Data source for read commands: auto (live with local fallback), live (API only), local (synced data only)")
 	rootCmd.PersistentFlags().StringVar(&flags.profileName, "profile", "", "Apply values from a saved profile (see 'printing-press-golden-pp-cli profile list')")
 	rootCmd.PersistentFlags().StringVar(&flags.deliverSpec, "deliver", "", "Route output to a sink: stdout (default), file:<path>, webhook:<url>")
diff --git a/testdata/golden/expected/generate-graphql-shared-endpoint/graphql-shared-golden/internal/cli/things_get.go b/testdata/golden/expected/generate-graphql-shared-endpoint/graphql-shared-golden/internal/cli/things_get.go
index 2f04632c..a19d2443 100644
--- a/testdata/golden/expected/generate-graphql-shared-endpoint/graphql-shared-golden/internal/cli/things_get.go
+++ b/testdata/golden/expected/generate-graphql-shared-endpoint/graphql-shared-golden/internal/cli/things_get.go
@@ -53,6 +53,24 @@ func newThingsGetCmd(flags *rootFlags) *cobra.Command {
 			if err != nil {
 				return classifyAPIError(err, flags)
 			}
+			// Inspect the mutate response body for a partial-failure-shaped
+			// field (e.g. Google Ads `partialFailureError`). Several Google
+			// APIs return 200 OK with a partial-failure field when some
+			// operations in the batch failed; ignoring it silently swallows
+			// real failures. Detection runs before output-mode selection so
+			// the exit code is consistent regardless of how stdout is
+			// rendered. --dry-run short-circuits because no real request
+			// was sent.
+			var partialFailure *partialFailureReport
+			if !flags.dryRun && statusCode >= 200 && statusCode < 300 {
+				partialFailure = detectPartialFailure(data)
+				if partialFailure != nil {
+					fmt.Fprintf(os.Stderr, "warning: partial failure detected in %s response: %s\n", "things", partialFailure.Message)
+					if len(partialFailure.ResourceNames) > 0 {
+						fmt.Fprintf(os.Stderr, "         succeeded: %d operation(s)\n", len(partialFailure.ResourceNames))
+					}
+				}
+			}
 			if wantsHumanTable(cmd.OutOrStdout(), flags) {
 				// Check if response contains an array (directly or wrapped in "data")
 				var items []map[string]any
@@ -60,6 +78,9 @@ func newThingsGetCmd(flags *rootFlags) *cobra.Command {
 					if err := printAutoTable(cmd.OutOrStdout(), items); err != nil {
 						fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 					} else {
+						if partialFailure != nil && !flags.allowPartialFailure {
+							return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "things", partialFailure.Message))
+						}
 						return nil
 					}
 				} else {
@@ -70,6 +91,9 @@ func newThingsGetCmd(flags *rootFlags) *cobra.Command {
 						if err := printAutoTable(cmd.OutOrStdout(), wrapped.Data); err != nil {
 							fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 						} else {
+							if partialFailure != nil && !flags.allowPartialFailure {
+								return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "things", partialFailure.Message))
+							}
 							return nil
 						}
 					}
@@ -77,6 +101,9 @@ func newThingsGetCmd(flags *rootFlags) *cobra.Command {
 			}
 			if flags.asJSON || (!isTerminal(cmd.OutOrStdout()) && !flags.csv && !flags.quiet && !flags.plain) {
 				if flags.quiet {
+					if partialFailure != nil && !flags.allowPartialFailure {
+						return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "things", partialFailure.Message))
+					}
 					return nil
 				}
 				// Apply --compact and --select to the API response before wrapping.
@@ -94,7 +121,10 @@ func newThingsGetCmd(flags *rootFlags) *cobra.Command {
 					"resource": "things",
 					"path":     path,
 					"status":   statusCode,
-					"success":  statusCode >= 200 && statusCode < 300,
+					"success":  statusCode >= 200 && statusCode < 300 && (partialFailure == nil || flags.allowPartialFailure),
+				}
+				if partialFailure != nil {
+					envelope["partial_failure"] = partialFailure
 				}
 				if flags.dryRun {
 					envelope["dry_run"] = true
@@ -111,9 +141,28 @@ func newThingsGetCmd(flags *rootFlags) *cobra.Command {
 				if err != nil {
 					return err
 				}
-				return printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true)
+				if perr := printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true); perr != nil {
+					return perr
+				}
+				if partialFailure != nil && !flags.allowPartialFailure {
+					return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "things", partialFailure.Message))
+				}
+				return nil
+			}
+			// Fall-through for mutate paths that did not hit the table or
+			// asJSON branches: --quiet, --csv, --plain, and default terminal
+			// raw output. printOutputWithFlags renders the body, then the
+			// typed partial-failure exit fires unless --allow-partial-failure
+			// downgrades it. Without this guard a partial failure would exit
+			// 0 for these output modes — the exact silent-swallow regression
+			// the surrounding patch is preventing for asJSON / piped output.
+			if perr := printOutputWithFlags(cmd.OutOrStdout(), data, flags); perr != nil {
+				return perr
+			}
+			if partialFailure != nil && !flags.allowPartialFailure {
+				return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "things", partialFailure.Message))
 			}
-			return printOutputWithFlags(cmd.OutOrStdout(), data, flags)
+			return nil
 		},
 	}
 	cmd.Flags().BoolVar(&stdinBody, "stdin", false, "Read request body as JSON from stdin")
diff --git a/testdata/golden/expected/generate-graphql-shared-endpoint/graphql-shared-golden/internal/cli/things_list.go b/testdata/golden/expected/generate-graphql-shared-endpoint/graphql-shared-golden/internal/cli/things_list.go
index b12420c0..15c1f5b6 100644
--- a/testdata/golden/expected/generate-graphql-shared-endpoint/graphql-shared-golden/internal/cli/things_list.go
+++ b/testdata/golden/expected/generate-graphql-shared-endpoint/graphql-shared-golden/internal/cli/things_list.go
@@ -49,6 +49,24 @@ func newThingsListCmd(flags *rootFlags) *cobra.Command {
 			if err != nil {
 				return classifyAPIError(err, flags)
 			}
+			// Inspect the mutate response body for a partial-failure-shaped
+			// field (e.g. Google Ads `partialFailureError`). Several Google
+			// APIs return 200 OK with a partial-failure field when some
+			// operations in the batch failed; ignoring it silently swallows
+			// real failures. Detection runs before output-mode selection so
+			// the exit code is consistent regardless of how stdout is
+			// rendered. --dry-run short-circuits because no real request
+			// was sent.
+			var partialFailure *partialFailureReport
+			if !flags.dryRun && statusCode >= 200 && statusCode < 300 {
+				partialFailure = detectPartialFailure(data)
+				if partialFailure != nil {
+					fmt.Fprintf(os.Stderr, "warning: partial failure detected in %s response: %s\n", "things", partialFailure.Message)
+					if len(partialFailure.ResourceNames) > 0 {
+						fmt.Fprintf(os.Stderr, "         succeeded: %d operation(s)\n", len(partialFailure.ResourceNames))
+					}
+				}
+			}
 			if wantsHumanTable(cmd.OutOrStdout(), flags) {
 				// Check if response contains an array (directly or wrapped in "data")
 				var items []map[string]any
@@ -56,6 +74,9 @@ func newThingsListCmd(flags *rootFlags) *cobra.Command {
 					if err := printAutoTable(cmd.OutOrStdout(), items); err != nil {
 						fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 					} else {
+						if partialFailure != nil && !flags.allowPartialFailure {
+							return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "things", partialFailure.Message))
+						}
 						return nil
 					}
 				} else {
@@ -66,6 +87,9 @@ func newThingsListCmd(flags *rootFlags) *cobra.Command {
 						if err := printAutoTable(cmd.OutOrStdout(), wrapped.Data); err != nil {
 							fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 						} else {
+							if partialFailure != nil && !flags.allowPartialFailure {
+								return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "things", partialFailure.Message))
+							}
 							return nil
 						}
 					}
@@ -73,6 +97,9 @@ func newThingsListCmd(flags *rootFlags) *cobra.Command {
 			}
 			if flags.asJSON || (!isTerminal(cmd.OutOrStdout()) && !flags.csv && !flags.quiet && !flags.plain) {
 				if flags.quiet {
+					if partialFailure != nil && !flags.allowPartialFailure {
+						return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "things", partialFailure.Message))
+					}
 					return nil
 				}
 				// Apply --compact and --select to the API response before wrapping.
@@ -90,7 +117,10 @@ func newThingsListCmd(flags *rootFlags) *cobra.Command {
 					"resource": "things",
 					"path":     path,
 					"status":   statusCode,
-					"success":  statusCode >= 200 && statusCode < 300,
+					"success":  statusCode >= 200 && statusCode < 300 && (partialFailure == nil || flags.allowPartialFailure),
+				}
+				if partialFailure != nil {
+					envelope["partial_failure"] = partialFailure
 				}
 				if flags.dryRun {
 					envelope["dry_run"] = true
@@ -107,9 +137,28 @@ func newThingsListCmd(flags *rootFlags) *cobra.Command {
 				if err != nil {
 					return err
 				}
-				return printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true)
+				if perr := printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true); perr != nil {
+					return perr
+				}
+				if partialFailure != nil && !flags.allowPartialFailure {
+					return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "things", partialFailure.Message))
+				}
+				return nil
+			}
+			// Fall-through for mutate paths that did not hit the table or
+			// asJSON branches: --quiet, --csv, --plain, and default terminal
+			// raw output. printOutputWithFlags renders the body, then the
+			// typed partial-failure exit fires unless --allow-partial-failure
+			// downgrades it. Without this guard a partial failure would exit
+			// 0 for these output modes — the exact silent-swallow regression
+			// the surrounding patch is preventing for asJSON / piped output.
+			if perr := printOutputWithFlags(cmd.OutOrStdout(), data, flags); perr != nil {
+				return perr
+			}
+			if partialFailure != nil && !flags.allowPartialFailure {
+				return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "things", partialFailure.Message))
 			}
-			return printOutputWithFlags(cmd.OutOrStdout(), data, flags)
+			return nil
 		},
 	}
 	cmd.Flags().BoolVar(&stdinBody, "stdin", false, "Read request body as JSON from stdin")
diff --git a/testdata/golden/expected/generate-public-param-names/public-param-golden/internal/cli/stores_create.go b/testdata/golden/expected/generate-public-param-names/public-param-golden/internal/cli/stores_create.go
index c8070688..23fdc7c1 100644
--- a/testdata/golden/expected/generate-public-param-names/public-param-golden/internal/cli/stores_create.go
+++ b/testdata/golden/expected/generate-public-param-names/public-param-golden/internal/cli/stores_create.go
@@ -55,6 +55,24 @@ func newStoresCreateCmd(flags *rootFlags) *cobra.Command {
 			if err != nil {
 				return classifyAPIError(err, flags)
 			}
+			// Inspect the mutate response body for a partial-failure-shaped
+			// field (e.g. Google Ads `partialFailureError`). Several Google
+			// APIs return 200 OK with a partial-failure field when some
+			// operations in the batch failed; ignoring it silently swallows
+			// real failures. Detection runs before output-mode selection so
+			// the exit code is consistent regardless of how stdout is
+			// rendered. --dry-run short-circuits because no real request
+			// was sent.
+			var partialFailure *partialFailureReport
+			if !flags.dryRun && statusCode >= 200 && statusCode < 300 {
+				partialFailure = detectPartialFailure(data)
+				if partialFailure != nil {
+					fmt.Fprintf(os.Stderr, "warning: partial failure detected in %s response: %s\n", "stores", partialFailure.Message)
+					if len(partialFailure.ResourceNames) > 0 {
+						fmt.Fprintf(os.Stderr, "         succeeded: %d operation(s)\n", len(partialFailure.ResourceNames))
+					}
+				}
+			}
 			if wantsHumanTable(cmd.OutOrStdout(), flags) {
 				// Check if response contains an array (directly or wrapped in "data")
 				var items []map[string]any
@@ -62,6 +80,9 @@ func newStoresCreateCmd(flags *rootFlags) *cobra.Command {
 					if err := printAutoTable(cmd.OutOrStdout(), items); err != nil {
 						fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 					} else {
+						if partialFailure != nil && !flags.allowPartialFailure {
+							return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "stores", partialFailure.Message))
+						}
 						return nil
 					}
 				} else {
@@ -72,6 +93,9 @@ func newStoresCreateCmd(flags *rootFlags) *cobra.Command {
 						if err := printAutoTable(cmd.OutOrStdout(), wrapped.Data); err != nil {
 							fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
 						} else {
+							if partialFailure != nil && !flags.allowPartialFailure {
+								return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "stores", partialFailure.Message))
+							}
 							return nil
 						}
 					}
@@ -79,6 +103,9 @@ func newStoresCreateCmd(flags *rootFlags) *cobra.Command {
 			}
 			if flags.asJSON || (!isTerminal(cmd.OutOrStdout()) && !flags.csv && !flags.quiet && !flags.plain) {
 				if flags.quiet {
+					if partialFailure != nil && !flags.allowPartialFailure {
+						return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "stores", partialFailure.Message))
+					}
 					return nil
 				}
 				// Apply --compact and --select to the API response before wrapping.
@@ -96,7 +123,10 @@ func newStoresCreateCmd(flags *rootFlags) *cobra.Command {
 					"resource": "stores",
 					"path":     path,
 					"status":   statusCode,
-					"success":  statusCode >= 200 && statusCode < 300,
+					"success":  statusCode >= 200 && statusCode < 300 && (partialFailure == nil || flags.allowPartialFailure),
+				}
+				if partialFailure != nil {
+					envelope["partial_failure"] = partialFailure
 				}
 				if flags.dryRun {
 					envelope["dry_run"] = true
@@ -113,9 +143,28 @@ func newStoresCreateCmd(flags *rootFlags) *cobra.Command {
 				if err != nil {
 					return err
 				}
-				return printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true)
+				if perr := printOutput(cmd.OutOrStdout(), json.RawMessage(envelopeJSON), true); perr != nil {
+					return perr
+				}
+				if partialFailure != nil && !flags.allowPartialFailure {
+					return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "stores", partialFailure.Message))
+				}
+				return nil
+			}
+			// Fall-through for mutate paths that did not hit the table or
+			// asJSON branches: --quiet, --csv, --plain, and default terminal
+			// raw output. printOutputWithFlags renders the body, then the
+			// typed partial-failure exit fires unless --allow-partial-failure
+			// downgrades it. Without this guard a partial failure would exit
+			// 0 for these output modes — the exact silent-swallow regression
+			// the surrounding patch is preventing for asJSON / piped output.
+			if perr := printOutputWithFlags(cmd.OutOrStdout(), data, flags); perr != nil {
+				return perr
+			}
+			if partialFailure != nil && !flags.allowPartialFailure {
+				return partialFailureErr(fmt.Errorf("partial failure in %s response: %s", "stores", partialFailure.Message))
 			}
-			return printOutputWithFlags(cmd.OutOrStdout(), data, flags)
+			return nil
 		},
 	}
 	cmd.Flags().StringVar(&bodyStoreCode, "store-code", "", "Store code")

← 80ba507e fix(ci): cancel-in-progress=false so cancelled check_runs do  ·  back to Cli Printing Press  ·  fix(cli): drop // PATCH marker instruction from generated AG caa68801 →