odysseus-dev/odysseus · warning · Error

data.error || ('HTTP ' + (data.status || 500))

Error message

data.error || ('HTTP ' + (data.status || 500))

What it means

HTTP 400 from POST /webhooks when the `name` form field, after strip() and truncation to MAX_NAME_LEN (100), is empty — i.e. missing, only whitespace, or a name composed solely of characters cut off by the 100-char truncation edge case. This is the first validation on webhook creation, before URL and events checks.

Source

Thrown at static/js/chat.js:6441

      let newText = '';

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        buffer += decoder.decode(value, { stream: true });
        const lines = buffer.split('\n');
        buffer = lines.pop() || '';

        for (const line of lines) {
          if (!line.startsWith('data: ')) continue;
          const payload = line.slice(6).trim();
          if (payload === '[DONE]') continue;
          try {
            const data = JSON.parse(payload);
            // The endpoint streams `event: error\ndata: {error,status}` on
            // failure — surface it instead of silently hanging on "Rewriting…".
            if (data.error) {
              throw new Error(data.error || ('HTTP ' + (data.status || 500)));
            }
            // Reasoning tokens (vLLM --reasoning-parser: Qwen3 / DeepSeek-R1)
            // arrive as separate {delta, thinking:true} chunks. They are NOT
            // the rewrite — fold them away so they don't pollute the result.
            if (data.thinking) continue;
            if (data.delta) {
              newText += data.delta;
              _killRwSpin();
              if (bodyEl) {
                bodyEl.innerHTML = markdownModule.processWithThinking(
                  markdownModule.squashOutsideCode(newText)
                );
              }
            }
          } catch (e) {
            if (e instanceof Error && e.message) throw e;  // re-throw real errors
            /* ignore JSON parse noise */
          }

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Include a non-empty `name` form field (1–100 chars) in the request.
  2. Ensure the field is sent as form data, not JSON — the parameters are Form('') so a JSON body yields defaults.
  3. Trim the name client-side and reject empty before submitting.
  4. Check for stray field-name typos (name vs title/label) in the client.

Example fix

# before
curl -X POST url/api/webhooks -H 'Content-Type: application/json' -d '{"url": "https://x.example/hook"}'

# after
curl -X POST url/api/webhooks -F 'name=deploy hook' -F 'url=https://x.example/hook' -F 'events=message.created'
Defensive patterns

Strategy: validation

Validate before calling

const name = (rawName ?? '').trim();
if (!name) return alert('Webhook name is required');
const fd = new FormData();
fd.set('name', name); // plus url, events, secret
await fetch('/api/webhooks', { method: 'POST', body: fd });

Type guard

function isCreatableWebhook(f: { name?: unknown }): boolean {
  return typeof f.name === 'string' && f.name.trim().length > 0 && f.name.trim().length <= 100;
}

Try / catch

const r = await fetch('/api/webhooks', { method: 'POST', body: fd });
if (r.status === 400) showFormError(await r.text()); // message names the failing field

Prevention

When it happens

Trigger: POST /webhooks (multipart/form or urlencoded) with name omitted, name=" ", or name="" — for example a curl call using -d that drops an empty field, or a UI form submitted before the name input was filled.

Common situations: Form field named differently than expected (e.g. 'label' instead of 'name') so FastAPI binds the default ''; client sends JSON body while the route expects Form fields; automated scripts creating webhooks from a config where one entry lacks a name.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/857a7156d6d70976. Report an issue: GitHub.