JuliusBrussee/caveman · error
must not contain a newline
Error message
${name} must not contain a newline What it means
bedrockCredentialEnvValue reads a Bedrock credential environment variable and rejects it if it contains a carriage return or newline. Newlines in credentials would corrupt the colon-joined credential string and downstream header/auth handling, so the wrapper fails fast with the variable name in the message.
Solutions
- Re-export the variable on a single line without surrounding whitespace: export AWS_BEARER_TOKEN_BEDROCK="<token>".
- Strip newlines when loading from a file: export AWS_BEARER_TOKEN_BEDROCK="$(tr -d '\r\n' < token.txt)".
- Check your .env / shell rc files for embedded line breaks or CRLF endings and fix them.
- Verify with: printf '%s' "$AWS_BEARER_TOKEN_BEDROCK" | od -c | grep -E '\\r|\\n'.
Example fix
// before export AWS_BEARER_TOKEN_BEDROCK="$(cat ~/bedrock-token.txt)" // after export AWS_BEARER_TOKEN_BEDROCK="$(tr -d '\r\n' < ~/bedrock-token.txt)"
Defensive patterns
Strategy: validation
Validate before calling
for (const name of ["AWS_BEARER_TOKEN_BEDROCK", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"]) {
const v = process.env[name];
if (typeof v === "string" && /[\r\n]/.test(v)) throw new Error(`${name} contains a newline; re-export it on one line`);
} Type guard
function isSingleLineCredential(v: unknown): v is string {
return typeof v === "string" && v.trim().length > 0 && !/[\r\n]/.test(v);
} Try / catch
try {
applyBedrockWrap(env, agent);
} catch (e) {
if (String((e as Error).message).endsWith("must not contain a newline")) {
// sanitize: env[name] = env[name].replace(/[\r\n]+/g, "") then retry once
}
} Prevention
- Use tr -d '\r\n' or xargs when exporting credentials from files.
- Keep .env files LF-only and single-line values, quoted.
- Check CI secret managers for automatic trailing newlines.
- Sanitize credential values at load time in wrapper scripts.
When it happens
Trigger: AWS_BEARER_TOKEN_BEDROCK, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or AWS_SESSION_TOKEN is set in the environment with a trailing/embedded newline or \r (e.g. from copy-paste, `export VAR=$(cat file)` on a file without -w, or a shell profile that wraps values).
Common situations: Pasting a bearer token from an editor that adds a newline; loading env from .env files with quoted multi-line values; CI secret managers that append newlines; Windows CRLF leaked into values.
Understand the failure class
Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.
Related errors
- AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must be set…
- awscreds: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must…
- awscreds: no AWS credentials found (env, web identity…
- bedrock: malformed AWS credentials (want…
- bedrock: missing AWS credentials in x-cave-upstream-key
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/af9c0b2c2a258227.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:9247
// auth header, then append exactly one current value when one is supplied.
function mergeAnthropicCustomHeader(raw: string | undefined, name: string, value: string | undefined): string {
const target = name.toLowerCase();
const kept = (raw ?? "")
.split(/\r\n|\n|\r/)
.filter((line) => {
if (!line.trim()) return false;
const colon = line.indexOf(":");
const headerName = (colon < 0 ? line : line.slice(0, colon)).trim().toLowerCase();
return headerName !== target;
});
if (value !== undefined) kept.push(`${name}: ${value}`);
return kept.join("\n");
}
function bedrockCredentialEnvValue(env: NodeJS.ProcessEnv, name: string): string | undefined {
const raw = env[name];
if (typeof raw !== "string" || !raw.trim()) return undefined;
if (/[\r\n]/.test(raw)) throw new Error(`${name} must not contain a newline`);
return raw.trim();
}
function bedrockUpstreamCredentialFromEnv(env: NodeJS.ProcessEnv): string | undefined {
const bearer = bedrockCredentialEnvValue(env, "AWS_BEARER_TOKEN_BEDROCK");
if (bearer) return bearer;
const accessKey = bedrockCredentialEnvValue(env, "AWS_ACCESS_KEY_ID");
const secretKey = bedrockCredentialEnvValue(env, "AWS_SECRET_ACCESS_KEY");
const sessionToken = bedrockCredentialEnvValue(env, "AWS_SESSION_TOKEN");
if (!accessKey && !secretKey && !sessionToken) return undefined;
if (!accessKey || !secretKey) {
throw new Error("AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must be set together");
}
return [accessKey, secretKey, ...(sessionToken ? [sessionToken] : [])].join(":");
}
// applyClaudeBedrockWrap selects Claude Code's native Bedrock or opt-in Mantle
// transport only when the operator explicitly requests it. The default ClaudeView on GitHub (pinned to 3ee70a1026)