projectlombok/lombok · error · AppException

Expected 3 lines in

Error message

Expected 3 lines in <path>: <LINE_DESCRIPTIONS>

What it means

After the line loop, readCreds requires that all four values were captured; bucketName==null means fewer than 4 non-empty lines were present (bucket is the 4th line). The message text misleadingly says 'Expected 3 lines' — it is a historical off-by-one; the file must contain 4 lines: accessKey/secretKey/endpoint/bucket (LINE_DESCRIPTIONS).

Solutions

  1. Add the missing line(s) to the file at <path> so it has exactly 4 non-empty lines: accessKey, secretKey, endpoint URL, bucket name.
  2. Ignore the '3' in the message text — it is an off-by-one in the message; follow LINE_DESCRIPTIONS and the 4-line template.
  3. Check for blank trailing lines / lines with only whitespace, which are skipped and thus not counted.
  4. Regenerate the file from the template in the NoSuchFileException message.

Example fix

// before (creds file, 3 lines -> throws)
AKIA...
secret...
https://12345.r2.cloudflarestorage.com
// after (4 lines)
AKIA...
secret...
https://12345.r2.cloudflarestorage.com
lombok-data
Defensive patterns

Strategy: validation

Validate before calling

List<String> lines = java.nio.file.Files.readAllLines(path).stream().map(String::trim).filter(l -> !l.isEmpty()).collect(java.util.stream.Collectors.toList());
if (lines.size() < 4) throw new IllegalStateException(path + " needs 4 lines (accessKey/secretKey/endpoint/bucket), found " + lines.size());

Prevention

When it happens

Trigger: Running the publish flow (go -> readCreds) when the creds file exists but has only 1-3 non-empty lines — e.g. the bucket-name line (or endpoint+bucket lines) is missing entirely, or trailing lines are blank.

Common situations: Users copy only the access key and secret from a cloud provider (no R2 endpoint), forget the last line after editing, or create the file per the outdated '3 lines' wording in this very message and omit the bucket name.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of projectlombok/lombok@6d6a3e9fec (2026-09-07). Data as JSON: /api/errors/0b80aea35d50bb16. Report an issue: GitHub.

Appendix: source

Thrown at src/support/lombok/publish/PublishToBucket.java:145

	}
	
	private static final String LINE_DESCRIPTIONS = "accessKey/secretKey/endpoint/bucket";
	private void readCreds(Path path) throws AppException {
		try {
			List<String> lines = Files.readAllLines(path);
			String accessKey = null, secretKey = null, endPoint = null, bucketName = null;
			for (String line : lines) {
				int idx = line.indexOf('#');
				if (idx != -1) line = line.substring(0, idx);
				line = line.trim();
				if (line.isEmpty()) continue;
				if (accessKey == null) { accessKey = line; continue; }
				if (secretKey == null) { secretKey = line; continue; }
				if (endPoint == null) { endPoint = line; continue; }
				if (bucketName == null) { bucketName = line; continue; }
				throw new AppException("Too many lines in " + path.toAbsolutePath() + " - only 4 expected: " + LINE_DESCRIPTIONS);
			}
			if (bucketName == null) throw new AppException("Expected 3 lines in " + path.toAbsolutePath() + ": " + LINE_DESCRIPTIONS);
			creds = AwsBasicCredentials.create(accessKey, secretKey);
			endpoint = URI.create(endPoint);
			this.bucketName = bucketName;
		} catch (NoSuchFileException e) {
			throw new AppException("File with bucket endpoint + credentials is not available. Make file " + path.toAbsolutePath() + "; it should contain something like: \n" +
				"123456789abcdef0123456789abcdef0  # this is the access key\n" +
				"123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0  # this is the secret\n" +
				"https://12345.r2.cloudflarestorage.com   # this is the endpoint\n" +
				"lombok-data   # this is the bucket name");
		} catch (IOException e) {
			throw new AppException("I/O issue reading creds file " + path.toAbsolutePath() + ": " + e.getClass() + ": " + e.getMessage());
		}
	}
}

View on GitHub (pinned to 6d6a3e9fec)