Skip to content

knowledge upload: rejection reasons reach the user in English only — the API composes prose where it should emit a code #17577

Open

Description

@mrveiss

Split from #17528's review, where it was raised as a blocker and measured as not one.

The gap

api/knowledge.py raises four distinguishable upload rejections, each as an English sentence:

Condition Sentence
oversize File too large. Maximum size is 10MB
disallowed extension File type not allowed. Allowed: …
extraction timeout Could not read '<name>' within <N>s…
no text layer No text layer found in any of the N page(s)… needs OCR. (#13884)

#17529 makes these reach the user, which they previously did not. They arrive in English in all eleven locales, because the backend composes prose and the frontend has nothing to map.

What this is NOT

It was put as "a regression for ten locales in exchange for an improvement in one." Measured on origin/main before #17529:

  • KnowledgeUpload.vue:302 renders {{ fileItem.errorMessage || $t('knowledge.upload.uploadFailed') }}
  • :865 sets errorMessage = err.message || 'Upload failed'
  • err.message was `HTTP ${status}: ${statusText}` — always truthy

So the translated fallback never rendered, and every locale already saw HTTP 400: Bad Request in English. #17529 changes untranslated generic to untranslated specific, equally everywhere. No locale loses a translation. The gap here predates it.

Why the obvious fixes are wrong

  • Translate the sentences in the frontend. Requires matching backend prose by string. The API may reword at any time and the match fails silently, degrading to the English it was meant to replace — a mapping whose failure mode is invisible.
  • Move the strings into the frontend. The backend needs them too: they appear in logs and in API responses to non-browser callers.

The shape that works

Have the endpoint emit a stable code beside the prose:

{ "detail": "File too large. Maximum size is 10MB",
  "detail_code": "upload.too_large",
  "detail_params": { "max_mb": 10 } }

The frontend maps detail_code to a translated key with parameters, and keeps detail as the fallback for any code it does not know. English prose stays the backend's, translation stays the frontend's, and an unmapped code degrades to today's behaviour rather than to nothing.

Acceptance criteria

  • POST /knowledge_base/upload emits detail_code for all four rejections, alongside the existing detail
  • detail_code values are stable identifiers, asserted by a backend test against the four raise sites
  • The frontend maps each to an i18n key present in all 11 locales
  • An unknown or absent detail_code falls back to the English detail — never to a generic message, which would undo fix(knowledge): an upload the backend refuses now says why it refused (#17528) #17529
  • A guard fails if a raise site gains a rejection without a detail_code

Not claimed

Whether other endpoints share this shape is unmeasured — I looked only at the upload path. If they do, the mapping belongs somewhere shared rather than in the upload UI, and that decision should be made before the first one is written.

Activity

  1. mrveiss commented on Oct 3, 2026

    @mrveiss
    OwnerAuthor

    Linked as a native sub-issue of #17527.

    What established it, stated so it can be revisited:

    So the parent was not inferred from the file path — it is where this issue's own pair already sits, on the same line and the same defect chain.

    How it was found. A closed-state duplicate sweep on a new axis: file:line citations appearing in both an open and a closed issue body. This pair was one of 30 such collisions. None of the 30 was a duplicate — the axis turns out to measure shared provenance rather than duplication, because siblings from one audit cite the same lines by construction. Three missing links fell out of it, and this was the best-evidenced.

    No scope, milestone, state or title changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions