ducaale/xh · warning
Using a combination of -X/--request and -L/--location which…
Error message
Using a combination of -X/--request and -L/--location which may cause unintended side effects.
What it means
When -L/--location (follow redirects) is combined with an explicit -X/--request method that is not GET, curl may replay the custom method against redirect targets, potentially causing unintended side effects (e.g. re-POSTing to a redirected host). xh's translate() warns about this when generating the curl command, mirroring curl's own documented caveat.
Solutions
- Remove -X/--request and let the method follow the redirect semantics (curl switches to GET for 301/302)
- Drop -L/--location if redirects should not be followed for this request
- Handle redirects manually (inspect the 3xx response and re-issue deliberately)
- If the target API requires method preservation across redirects, configure curl's POST301/POST302 options explicitly in the generated command
Example fix
# before xh --curl -L -X POST example.org/login # after (let redirect semantics choose the method) xh --curl -L example.org/login # or keep POST but do not follow redirects xh --curl -X POST example.org/login
Defensive patterns
Strategy: validation
Validate before calling
# Reject -L with a non-GET -X before running case "$method" in GET|"") : ;; *) if [ "$follow" = "1" ]; then echo "warning: -L with -X $method may replay $method on redirects"; fi ;; esac
Prevention
- Avoid -X with -L unless you understand redirect method semantics
- For POST-then-redirect flows, let the server's 301/302 downgrade to GET naturally
- Inspect redirect chains with --verbose before enabling -L in production scripts
- Never blind-add -L to all curl commands in wrapper scripts
When it happens
Trigger: Calling translate() with args.follow == true and args.method set to something other than GET (e.g. POST/PUT/DELETE) while --curl/--curl-long output is requested.
Common situations: Following a 301/302 redirect after a POST login or payment call; APIs behind CDNs that redirect; scripts that blindly add -L to every curl command while also using -X POST.
Understand the failure class
Background: "mutually exclusive" flag errors: what "can't supply both nx and xx", "--raw is not compatible with -i" and "cannot be used with" mean, and how to fix them — this error's family across 29 libraries.
Related errors
- Invalid UTF-8
- JSON values are not supported in multipart fields
- -I/--head is incompatible with sending data. Consider…
- Inferred port number in --resolve from request URL.
- Ignored
AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13).
Data as JSON: /api/errors/7a3aeb9105d28a08.
Report an issue: GitHub.
Appendix: source
Thrown at src/to_curl.rs:131
// Already the default
(args.all, "--all"),
// No (straightforward?) equivalent
(args.history_print.is_some(), "-P/--history-print"),
// Might be possible to emulate with --cookie-jar but tricky
(args.session.is_some(), "--session"),
// Already the default (usually, depends on compile time options)
// Unclear if you can even change this at runtime
(args.native_tls, "--native-tls"),
];
for (present, flag) in ignored {
if present {
cmd.warn(format!("Ignored {flag}"));
}
}
if args.follow && !matches!(args.method, Some(Method::GET) | None) {
cmd.warn("Using a combination of -X/--request and -L/--location which may cause unintended side effects.");
}
// Silently ignored:
// - .ignore_stdin: assumed by default
// (to send stdin, --data-binary @- -H 'Content-Type: application/octet-stream')
// - .curl and .curl_long: you are here
// Output options
if args.verbose > 0 {
// Far from an exact match, but it does print the request headers
cmd.opt("-v", "--verbose");
}
if args.quiet > 0 {
// Also not an exact match but it suppresses error messages which
// is sorta like suppressing warnings
cmd.opt("-s", "--silent");
}
if args.debug {View on GitHub (pinned to 2404aceecc)