different-ai/openwork · error · ApiError
invalid_payload
invalid_payload
Error message
providers must be an array of non-empty strings
What it means
This 400 invalid_payload error is thrown by parseDisabledProvidersPayload when the request body is not a JSON array. The disabled-providers update endpoint expects an array of provider name strings, so any other top-level shape (object, string, null, missing body) is rejected before any validation of elements occurs.
Source
Thrown at apps/server/src/server.ts:286
}
function runtimeConfigKeys(config: RuntimeOpencodeConfig): string[] {
const keys: string[] = [];
if (config.default_agent) keys.push("default_agent");
if (Array.isArray(config.plugin) && config.plugin.length) keys.push("plugin");
if (Array.isArray(config.disabled_providers) && config.disabled_providers.length) keys.push("disabled_providers");
if (isRecord(config.mcp) && Object.keys(config.mcp).length) keys.push("mcp");
const permission = isRecord(config.permission) ? config.permission : null;
if (permission && isRecord(permission.external_directory) && Object.keys(permission.external_directory).length) {
keys.push("permission");
}
if (isRecord(config.provider) && Object.keys(config.provider).length) keys.push("provider");
return keys;
}
function parseDisabledProvidersPayload(value: unknown): string[] {
if (!Array.isArray(value)) {
throw new ApiError(400, "invalid_payload", "providers must be an array of non-empty strings");
}
const providers: string[] = [];
for (const entry of value) {
if (typeof entry !== "string" || !entry.trim()) {
throw new ApiError(400, "invalid_payload", "providers must be an array of non-empty strings");
}
const provider = entry.trim();
if (!providers.includes(provider)) providers.push(provider);
}
return providers;
}
function parseRuntimeProviderPatchPayload(body: Record<string, unknown>): Record<string, unknown> {
const provider = body.provider;
if (!isRecord(provider)) {
throw new ApiError(400, "invalid_payload", "provider must be an object");
}
for (const [providerId, value] of Object.entries(provider)) {View on GitHub (pinned to 2b7df46e8a)
Solutions
- Send a raw JSON array as the body: ["anthropic", "openai"]
- Ensure Content-Type: application/json and JSON.stringify the array
- Check API docs for the exact endpoint payload shape
Example fix
// before
await fetch(url, { body: JSON.stringify({ providers: ["anthropic"] }) });
// after
await fetch(url, { body: JSON.stringify(["anthropic"]), headers: { "Content-Type": "application/json" } }); Defensive patterns
Strategy: validation
Validate before calling
if (!Array.isArray(providers)) throw new Error("providers must be a JSON array"); Type guard
const isStringArray = (v: unknown): v is string[] => Array.isArray(v) && v.every(x => typeof x === "string");
Try / catch
try {
await setDisabledProviders(body);
} catch (e) {
if (e.code === "invalid_payload") console.error("send a raw array: [\"anthropic\"]", e.message);
else throw e;
} Prevention
- Never wrap the list in an object key
- Always JSON.stringify and set Content-Type: application/json
- Validate payload shape with Zod before sending
When it happens
Trigger: Calling the disabled-providers PATCH/PUT endpoint with body that is not an array, e.g. {"providers": ["anthropic"]} instead of ["anthropic"], or an empty/absent body.
Common situations: Wrapping the list in an object by mistake; sending form-encoded or stringified JSON with wrong Content-Type; older clients using a different payload shape.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/9fc82b567b69d18a.
Report an issue: GitHub.