apache/pulsar · warning · RestException
Target URL is required
Error message
Target URL is required
What it means
A 400 BAD_REQUEST thrown by the metadata migration admin endpoint (MetadataMigrationBase.startMigration) when the required 'target' query parameter is missing or blank. The migration framework needs the target metadata store URL (e.g. a RocksDB or Etcd/metastore URL) to copy metadata to.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/MetadataMigrationBase.java:92
}
@POST
@Path("/start")
@Operation(summary = "Start metadata store migration")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "Migration started successfully"),
@ApiResponse(responseCode = "400", description = "Invalid target URL"),
@ApiResponse(responseCode = "409", description = "Migration already in progress"),
@ApiResponse(responseCode = "500", description = "Internal server error")
})
public void startMigration(
@Parameter(description = "Target metadata store URL", required = true)
@QueryParam("target")
String targetUrl) {
validateSuperUserAccess();
if (targetUrl == null || targetUrl.trim().isEmpty()) {
throw new RestException(Response.Status.BAD_REQUEST, "Target URL is required");
}
try {
// Check if metadata store is wrapped with DualMetadataStore
if (!(pulsar().getLocalMetadataStore() instanceof DualMetadataStore dualStore)) {
throw new RestException(Response.Status.BAD_REQUEST, "Metadata store is not configured for migration. "
+ "Please ensure you're using a supported source metadata store (e.g., ZooKeeper).");
}
// Reject the request if a migration is already in progress or was completed. The migration
// flag is always kept in the source store, so read it from there: after a completed
// migration the dual store would route the read to the target store.
var existingFlag = dualStore.getSourceStore().get(MigrationState.MIGRATION_FLAG_PATH).get();
if (existingFlag.isPresent()) {
MigrationState currentState = ObjectMapperFactory.getMapper().reader()
.readValue(existingFlag.get().getValue(), MigrationState.class);
switch (currentState.getPhase()) {
case PREPARATION, COPYING -> throw new RestException(Response.Status.CONFLICT,View on GitHub (pinned to 820761864e)
Solutions
- Pass the target metadata store URL, e.g. ?target=rocksdb:/data/target-metadata.
- Ensure the parameter name is exactly 'target' and non-empty after trimming.
- URL-encode the target URL if it contains special characters like ? or &.
Example fix
// before curl -X POST http://broker:8080/admin/v3/migration // after curl -X POST 'http://broker:8080/admin/v3/migration?target=rocksdb%3A%2Fdata%2Ftarget-metadata'
Defensive patterns
Strategy: validation
Validate before calling
if (!targetUrl || targetUrl.trim().isEmpty()) {
throw new IllegalArgumentException("?target=<metadata store URL> is required");
} Try / catch
try { startMigration(target); }
catch (PulsarAdminException e) {
if (e.getStatusCode() == 400) { /* fix the query parameter and retry */ }
else throw e;
} Prevention
- Always pass ?target= with a non-blank store URL
- URL-encode the target URL
- Read the endpoint's @QueryParam documentation before scripting
When it happens
Trigger: Calling POST/PUT on the metadata-migration admin path without the ?target= query parameter, or with target= (empty) or only whitespace.
Common situations: Copy/pasting the endpoint example without the query param; URL encoding issue dropping the value; forgetting the target URL after configuring only the source/dual store.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- Metadata store is not configured for migration. Please ensur
- <validation message from IllegalArgumentException>
- %s %s doesn't have instance with id %s
- Function in trigger function has more than 1 input topics
- Function in trigger function has unidentified topic
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/731b5da82197f179.
Report an issue: GitHub.