spring-projects/spring-boot · error · IOException

' exited with code

Error message

%s' exited with code %d: %s

What it means

CredentialHelper.get invokes an external credential helper binary (e.g. docker-credential-*), writes the server URL to its stdin, and reads the response. If the helper exits non-zero with a message that is NOT the credentials-not-found sentinel, the plugin throws IOException carrying the process identity, exit code, and stderr. Credentials-not-found is intentionally NOT an error and returns null.

Solutions

  1. Inspect the captured stderr and exit code in the exception message
  2. Run the helper directly to reproduce: echo $SERVER_URL | docker-credential-XXX get
  3. Re-authenticate / refresh tokens, or remove the broken credsStore entry from ~/.docker/config.json
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the helper exists and is executable before invoking
Path helper = Path.of("/usr/local/bin/docker-credential-" + name);
if (!Files.isExecutable(helper)) { throw new IllegalStateException("credential helper missing: " + helper); }

Try / catch

try { CredentialHelper.get(...); } catch (IOException ex) { log.error("Credential helper failed: {}", ex.getMessage()); /* prompt re-auth or fall back */ }

Prevention

When it happens

Trigger: The configured credential helper exists and ran but errored: auth failure, malformed helper config, helper crash, expired token.

Common situations: Misconfigured docker-credential-ecr-login for AWS ECR; expired OAuth tokens; helper pointing at a missing keychain; corrupt ~/.docker/config.json with a credsStore entry pointing to a broken helper.

Related errors


AI-assisted analysis of spring-projects/spring-boot@270dfe353f (2026-08-11). Data as JSON: /api/errors/883810c73a0b6d09. Report an issue: GitHub.

Appendix: source

Thrown at buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/CredentialHelper.java:71

	CredentialHelper(String executable) {
		this.executable = executable;
	}

	@Nullable Credential get(String serverUrl) throws IOException {
		ProcessBuilder processBuilder = processBuilder("get");
		Process process = start(processBuilder);
		try (OutputStream request = process.getOutputStream()) {
			request.write(serverUrl.getBytes(StandardCharsets.UTF_8));
		}
		try {
			int exitCode = process.waitFor();
			try (InputStream response = process.getInputStream()) {
				if (exitCode == 0) {
					return new Credential(SharedJsonMapper.get().readTree(response));
				}
				String errorMessage = new String(response.readAllBytes(), StandardCharsets.UTF_8);
				if (!isCredentialsNotFoundError(errorMessage)) {
					throw new IOException("%s' exited with code %d: %s".formatted(process, exitCode, errorMessage));
				}
				return null;
			}
		}
		catch (InterruptedException ex) {
			Thread.currentThread().interrupt();
			return null;
		}
	}

	private ProcessBuilder processBuilder(String action) {
		ProcessBuilder processBuilder = new ProcessBuilder().redirectErrorStream(true);
		if (Platform.isWindows()) {
			processBuilder.command("cmd", "/c");
		}
		processBuilder.command().addAll(Arrays.asList(this.executable, action));
		return processBuilder;
	}

View on GitHub (pinned to 270dfe353f)