apify/crawlee · error · Error
Request options are not valid, the 'url' property is not a s
Error message
Request options are not valid, the 'url' property is not a string. Input: ${inspect(opts)} What it means
RequestQueue.addRequestsBatched() streams inputs through generateRequests(), validating each item. If an object provides a url property that is defined but not a string (number, object, null, array), the library rejects it because Request construction requires a string URL.
Source
Thrown at packages/core/src/storages/request_queue.ts:598
* @param options Options for the request queue
*/
async addRequestsBatched(
requests: ReadonlyDeep<RequestsLike>,
options: AddRequestsBatchedOptions = {},
): Promise<AddRequestsBatchedResult> {
parseArgument(requests, iterableSchema);
const { forefront, waitForAllRequestsToBeAdded, batchSize, waitBetweenBatchesMillis, maxNewRequests } =
parseArgument(options, addRequestsBatchedOptionsSchema);
const addRequest = this.addRequest.bind(this);
async function* generateRequests() {
for await (const opts of requests) {
// Validate the input
if (typeof opts === 'object' && opts !== null) {
if (opts.url !== undefined && typeof opts.url !== 'string') {
throw new Error(
`Request options are not valid, the 'url' property is not a string. Input: ${inspect(opts)}`,
);
}
if (opts.id !== undefined) {
throw new Error(
`Request options are not valid, the 'id' property must not be present. Input: ${inspect(opts)}`,
);
}
if (
(opts as any).requestsFromUrl !== undefined &&
typeof (opts as any).requestsFromUrl !== 'string'
) {
throw new Error(
`Request options are not valid, the 'requestsFromUrl' property is not a string. Input: ${inspect(opts)}`,
);
}View on GitHub (pinned to dbe57fb09c)
Solutions
- Sanitize inputs: keep only items where typeof url === 'string' and non-empty
- Coerce valid values (e.g. String(row.url)) and drop invalid rows before adding
- Fix upstream data extraction producing non-string urls
- Add strict typing/DTO validation (zod etc.) on incoming request sources
Example fix
// before
await requestQueue.addRequestsBatched(rows.map(r => ({ url: r.url }))); // r.url may be null
// after
const valid = rows.filter(r => typeof r.url === 'string' && r.url.length > 0)
.map(r => ({ url: r.url }));
await requestQueue.addRequestsBatched(valid); Defensive patterns
Strategy: type-guard
Validate before calling
const valid = requests.filter(r => !(r && typeof r === 'object' && 'url' in r) || typeof r.url === 'string');
Type guard
function hasStringUrl(r) {
return r === null || typeof r !== 'object' || r.url === undefined || typeof r.url === 'string';
} Try / catch
try {
await queue.addRequestsBatched(requests);
} catch (err) {
if (err.message.includes("'url' property is not a string")) {
logger.error(`Invalid request options: ${err.message}`);
} else throw err;
} Prevention
- Sanitize/coerce url fields to strings before enqueuing
- Validate external data (CSV/JSON/API) with a schema library
- Type inputs as Array<Partial<RequestOptions> | string> strictly
When it happens
Trigger: Passing an async iterable/array to addRequestsBatched where an item has url: null, url: 123, url: {...}; data from parsed JSON/CSV where url is missing-but-keyed or numeric; TypeScript types bypassed.
Common situations: Importing scraped data where the url column is empty/NaN; mapping API responses with inconsistent field types; template objects with url accidentally set to a nested object.
Related errors
- Request options are not valid, the 'requestsFromUrl' propert
- Cannot create Request from type: ${type}
- Request options are not valid, the 'id' property must not be
- The `requestManager` option cannot be used in conjunction wi
- Expected an iterable or async iterable, got ${getObjectType(
AI-assisted analysis of apify/crawlee@dbe57fb09c (2026-08-30).
Data as JSON: /api/errors/15db979abeac9050.
Report an issue: GitHub.