unslothai/unsloth · warning · ValueError

fill_absent_fields cannot be combined with remove.

Error message

fill_absent_fields cannot be combined with remove.

What it means

HTTP 409 from PUT /settings/openai-auto-switch/overrides when the payload sets both fill_absent_fields=true and remove=true. The route raises this ValueError deliberately (mapped to 409): a request that simultaneously fills absent fields and deletes the override entry has no coherent meaning — honoring either would silently lose or resurrect settings. It is a request-shape guard, fired before any write happens, so no state changes.

Source

Thrown at studio/backend/routes/settings.py:1255

    def wrapper(*args, **kwargs):
        with _override_write_lock:
            return func(*args, **kwargs)

    return wrapper


@router.put("/openai-auto-switch/overrides", response_model = ModelOverridesResponse)
@_serialized_override_write
def update_openai_auto_switch_override(
    payload: ModelOverridePayload, current_subject: str = Depends(get_current_subject)
) -> ModelOverridesResponse:
    from core.inference.llama_server_args import drop_managed_flags, validate_extra_args
    from utils.openai_auto_switch_settings import get_model_override

    try:
        if payload.fill_absent_fields and payload.remove is True:
            # A fill that is also a delete has no meaning; picking one loses or resurrects.
            raise ValueError("fill_absent_fields cannot be combined with remove.")
        # Only model_id is the documented "remove"; otherwise omitted flags carry over.
        requested_extra_args = payload.llama_extra_args
        # fill_absent_fields is a write mode, not a saved field: leaving it in would make
        # every payload look non-empty and break the legacy "no fields means remove".
        saved_fields = payload.model_dump(
            exclude = {"model_id", "llama_extra_args", "remove", "fill_absent_fields"},
            exclude_none = True,
        )
        if payload.remove is not None:
            is_removal = payload.remove
        else:
            is_removal = not payload.tensor_parallel and not {
                key: value for key, value in saved_fields.items() if key != "tensor_parallel"
            }
        if requested_extra_args is None and not is_removal:
            stored = get_model_override(payload.model_id)
            # A fill keeps the stored flags without echoing them back through validation: one
            # denylisted since it was saved would 400 the migration, which then retries forever.

View on GitHub (pinned to 203007d190)

Solutions

  1. Pick one mode: to delete, send remove:true (and omit fill_absent_fields or set false); to fill, send fill_absent_fields:true with remove:false/omitted.
  2. In the client, make fill and remove mutually exclusive controls (radio, not checkboxes).
  3. Strip remove from the payload object when the user chose 'fill and save'.

Example fix

// before
await api.put('/settings/openai-auto-switch/overrides', { model_id, fill_absent_fields: true, remove: true, ...fields }); // 409

// after
const payload = { model_id, ...fields };
if (mode === 'delete') payload.remove = true;
else if (mode === 'fill') payload.fill_absent_fields = true;
await api.put('/settings/openai-auto-switch/overrides', payload);
Defensive patterns

Strategy: validation

Validate before calling

if (payload.fill_absent_fields && payload.remove === true) {
  throw new Error('Choose fill OR remove, not both');
}
await api.put('/settings/openai-auto-switch/overrides', payload);

Type guard

function isCoherentOverridePayload(p: { fill_absent_fields?: boolean; remove?: boolean | null }): boolean {
  return !(p.fill_absent_fields === true && p.remove === true);
}

Try / catch

try { await api.put('/settings/openai-auto-switch/overrides', payload); }
catch (e) {
  if (e.status === 409 && /fill_absent_fields/.test(e.detail)) { delete payload.remove; return api.put(url, payload); }
  throw e;
}

Prevention

When it happens

Trigger: PUT overrides with {model_id, fill_absent_fields: true, remove: true} — e.g. a form that merges 'fill missing fields' and 'delete this entry' checkboxes, or a client that hard-codes remove:true on every save while also passing the fill flag.

Common situations: UI mode toggle left on when the user clicks Delete; payloads built by spread of defaults ({...defaults, remove:true}) that inherit fill_absent_fields:true; API wrappers always sending both flags.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/de0c8b9f605dc932. Report an issue: GitHub.