odysseus-dev/odysseus · warning · ValueError
not an object
Error message
not an object
What it means
ValueError('not an object') raised inside POST /api/tasks/parse when the LLM's reply parses as valid JSON but is not a top-level object (e.g. a bare array or string). The handler strips markdown fences, extracts the first {...} block, json.loads it, then requires isinstance(draft, dict). The surrounding try/except converts it to a 200 response with success:false and message 'not an object' — a model-output quality failure, not a server fault.
Source
Thrown at routes/task_routes.py:1152
url, model, headers = resolve_endpoint("default", owner=user or None)
if not (url and model):
return {"success": False, "message": "No model endpoint configured"}
raw = await llm_call_async(
url=url, model=model,
messages=[{"role": "system", "content": sys},
{"role": "user", "content": desc[:1000]}],
temperature=0.2, max_tokens=400, headers=headers, timeout=45,
)
text = _strip_think(raw or "", prose=False, prompt_echo=False).strip()
if text.startswith("```"):
text = text.strip("`")
if text.lower().startswith("json"):
text = text[4:].lstrip()
# Pull the first {...} block in case the model added stray text.
m = _re.search(r"\{.*\}", text, _re.S)
draft = _json.loads(m.group(0) if m else text)
if not isinstance(draft, dict):
raise ValueError("not an object")
# Whitelist + light validation so the frontend gets clean fields.
out: Dict[str, Any] = {}
if draft.get("task_type") in ("llm", "research"):
out["task_type"] = draft["task_type"]
else:
out["task_type"] = "llm"
for k in ("name", "prompt", "cron_expression", "scheduled_date"):
if isinstance(draft.get(k), str) and draft[k].strip():
out[k] = draft[k].strip()
if draft.get("schedule") in ("daily", "weekly", "monthly", "once", "cron"):
out["schedule"] = draft["schedule"]
else:
out["schedule"] = "daily"
st = draft.get("scheduled_time")
if isinstance(st, str) and _re.match(r"^\d{1,2}:\d{2}$", st.strip()):
out["scheduled_time"] = st.strip()
if isinstance(draft.get("scheduled_day"), int):
out["scheduled_day"] = draft["scheduled_day"]View on GitHub (pinned to f9235ebbf1)
Solutions
- Retry the request — non-dict outputs are typically non-deterministic at temperature 0.2
- Switch the 'utility' (or fallback 'default') endpoint to a stronger instruction-following model via resolve_endpoint configuration
- Shorten/simplify the description input so the model stays within max_tokens=400
- Inspect the logged output (logger.error('parse_task failed: ...')) to see what shape the model actually returned
Example fix
// before: model returns ["step1","step2"] -> success:false
// after: strengthen the system prompt and budget
"Output ONLY a single JSON object enclosed in { }. Never an array, string, or multiple objects.")
llm_call_async(..., max_tokens=800, ...) Defensive patterns
Strategy: retry
Validate before calling
// Pre-validate the description before calling /parse if (!description || description.trim().length < 3) return skipParse();
Type guard
function isTaskDraft(v: unknown): v is Record<string, unknown> {
return typeof v === 'object' && v !== null && !Array.isArray(v);
} Try / catch
const r = await parseTask(desc);
if (!r.success) { if (r.message === 'not an object') return retryOnce(desc); else return manualForm(); } Prevention
- Retry once — LLM shape errors are transient at temperature 0.2
- Always branch on response.success, not HTTP status (this route returns 200 with success:false)
- Keep descriptions short so the model stays within max_tokens
When it happens
Trigger: POST /api/tasks/parse with a description for which the model emits a JSON array or bare scalar instead of an object; or a reply whose first {...} extraction yields a non-dict value.
Common situations: Utility/default model endpoint misconfigured or pointed at a model that rambles; max_tokens=400 truncating the JSON so the {...} regex grabs a fragment; prompt-injection-style input that makes the model answer with a list of steps.
Related errors
- Prompt is required for LLM/research tasks
- Failed to create task
- Invalid JSON
- Expected a JSON object
- Invalid JSON: {e}
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/1c9e76a4dc622368.
Report an issue: GitHub.