theonedev/onedev · error · io.onedev.server.exception.NotAcceptableException
Reason is required
Error message
Reason is required
What it means
When submitting a job through TodResource, a human-readable 'reason' string is mandatory; it is recorded as the audit context passed to jobService.submit (and resubmit). A null/blank reason causes NotAcceptableException before any build is created.
Source
Thrown at server-core/src/main/java/io/onedev/server/ai/TodResource.java:1735
params = new HashMap<String, List<String>>();
List<String> paramPairs = (List<String>) paramData;
if (paramPairs != null) {
for (var paramPair: paramPairs) {
var paramName = trimToNull(StringUtils.substringBefore(paramPair, "="));
var paramValue = trimToNull(StringUtils.substringAfter(paramPair, "="));
if (paramName != null && paramValue != null)
params.computeIfAbsent(paramName, k -> new ArrayList<>()).add(paramValue);
}
}
} else if (paramData instanceof Map) {
params = (Map<String, List<String>>) paramData;
} else {
params = new HashMap<String, List<String>>();
}
var reason = trimToNull((String)data.get("reason"));
if (reason == null)
throw new NotAcceptableException("Reason is required");
var build = jobService.submit(user, project, ObjectId.fromString(commitHash), jobName,
params, refName, null, null, reason);
if (build.isFinished())
jobService.resubmit(user, build, reason);
var summary = BuildHelper.getSummary(project, build);
summary.put("id", build.getId());
return summary;
}
@Path("/get-clone-roots")
@GET
public Map<String, String> getCloneRoots() {
if (SecurityUtils.getUser() == null)
throw new UnauthenticatedException();
var cloneRoots = new HashMap<String, String>();View on GitHub (pinned to d44925c47c)
Solutions
- Set data.put("reason", "<why this build is being submitted>") before calling the endpoint.
- Generate a default reason programmatically if none is available (e.g. 'triggered by AI agent').
- Audit your tool-calling layer to always populate the reason field.
Example fix
// before
var data = Map.of("branch", "main", "jobName", "ci");
// after
var data = Map.of("branch", "main", "jobName", "ci", "reason", "manual rebuild requested by user"); Defensive patterns
Strategy: validation
Validate before calling
if (!(data.reason ?? "").trim()) throw new Error("reason is required for job submission"); Type guard
function hasReason(d) { return typeof d.reason === "string" && d.reason.trim().length > 0; } Try / catch
try { submit(data); } catch (e) { if (e.status === 406 && e.message.includes("Reason is required")) { data.reason = "automated submission"; return submit(data); } throw e; } Prevention
- Make 'reason' a mandatory field in your automation's submit template
- Auto-generate contextual reasons (user, ticket, trigger source)
- Keep audit-friendly reasons even for fully automated flows
When it happens
Trigger: Calling the job-submit tool endpoint with a valid commitHash/branch/tag and params, but data.get("reason") null or empty.
Common situations: AI agents or scripts automating build submissions that treat 'reason' as optional metadata; refactors of tool payloads that drop the reason field.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Ref name is required when commit hash is specified
- Either commit hash, branch or tag should be specified
- ${e.getMessage()}
- Reviewer not found:
- Assignee not found:
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/f948b36c92091db3.
Report an issue: GitHub.