Errori ed esiti delle scansioni
Questa è la pagina di riferimento per la gestione degli errori: il corpo dell’errore restituito da ogni endpoint, i codici in base ai quali vale la pena creare diramazioni e, soprattutto, le tabelle canoniche degli esiti delle scansioni. Una “nessuna corrispondenza” è un risultato, non un errore di trasporto, e viene comunque restituita con uno stato HTTP di errore. Il codice che considera ogni risposta non 2xx un bug segnalerà interruzioni del servizio mai avvenute.
Gli schemi specifici per ciascun endpoint si trovano nel riferimento API. I flussi sono descritti in Identificatori e nella guida introduttiva.
La struttura degli errori
Sezione intitolata “La struttura degli errori”Ogni richiesta non riuscita restituisce lo stesso oggetto JSON:
{ "code": "IDENTIFIER_NOT_FOUND", "message": "No match in the 3 searched teams", "status": 404, "detail": { "outcome": "no_match", "teamsSearched": 3, "scan": { "scanId": "…", "fingerprintId": "…", "dustId": null } }}| Campo | Tipo | Significato |
|---|---|---|
code | string | Codice stabile leggibile dalla macchina. Crea diramazioni in base a questo campo. Non analizzare mai message. |
message | string | Testo leggibile dalle persone, localizzato in base a Dust-Ctx-Locale. La formulazione cambia; i codici no. |
status | number | Rispecchia lo stato HTTP. |
detail | object, facoltativo | Contesto specifico dell’errore: dettagli della convalida, ricevuta di scansione, classificazione dell’esito, ID in conflitto. |
status e lo stato HTTP coincidono sempre, quindi puoi creare diramazioni in base all’uno o all’altro. Ogni risposta, riuscita o meno, contiene anche un’intestazione x-request-id. Registrala nei log; l’assistenza la utilizza per individuare la tua richiesta esatta.
Codici per classe
Sezione intitolata “Codici per classe”Richiesta e autorizzazione
Sezione intitolata “Richiesta e autorizzazione”| Codice | Stato | Quando |
|---|---|---|
INVALID_REQUEST | 400 | Corpo, query o intestazione con formato non valido. I dettagli della convalida si trovano in detail. |
INVALID_DATA | 400 | La richiesta è stata analizzata, ma i valori non possono essere utilizzati (per esempio, un payload di identificazione che il servizio di scansione non è riuscito a leggere). |
UNAUTHORIZED | 401 | Token bearer mancante, scaduto o non valido. |
FORBIDDEN | 403 | L’autenticazione è riuscita, ma questo contesto non può eseguire l’operazione. |
ATTRIBUTION_REQUIRED | 403 | Il criterio di attribuzione dell’account di servizio è required e la scrittura non includeva alcun Dust-Ctx-Declared-Actor. |
ORG_ID_REQUIRED / TEAM_ID_REQUIRED | 400 | Manca un’intestazione di contesto in un endpoint con ambito definito. |
NOT_FOUND / NO_DATA_FOUND | 404 | In questo contesto non è visibile alcun registro corrispondente. |
RATE_LIMITED | 429 | Attendi con backoff e riprova. |
THREAD_DATA_CONFLICT | 409 | Conflitto di concorrenza ottimistica: il tuo expectedUpdatedAt è obsoleto. Leggi di nuovo e riapplica le modifiche. |
COMPOSITE_TAG_CONFLICT | 409 | Conflitto dell’etichetta: un DUST già presente su un’altra etichetta o associato altrove, una posizione della bobina occupata oppure la rimozione dell’ultimo identificatore di un’etichetta. detail.reason indica quale caso si è verificato. |
UNKNOWN_ERROR / SERVICE_ERROR | 500 | Errore lato server. Riprova con backoff; se persiste, includi l’ID della richiesta. |
Identificatori e scansioni
Sezione intitolata “Identificatori e scansioni”| Codice | Stato | Significato |
|---|---|---|
IDENTIFIER_NOT_FOUND | 404 | Mancata corrispondenza definitiva: ogni partizione interrogata ha risposto e non è stata trovata alcuna corrispondenza. |
IDENTIFIER_NOT_BOUND | 404 | L’identificatore esiste, ma non è associato ad alcuna Scheda (raggiungibile solo tramite un’identificazione per tagId). |
IDENTIFIER_ALREADY_BOUND | 409 | Associazione rifiutata: quell’identificatore (o la relativa etichetta) è già presente su un’altra Scheda. detail.compositeTagId indica l’etichetta. |
IDENTIFIER_VERIFY_FAILED | 500 | La verifica del singolo identificatore non ha trovato una corrispondenza oppure l’identificatore specificato non è associato a quella Scheda. |
SCAN_AMBIGUOUS_MATCH | 409 | Due o più DUST distinti registrati hanno prodotto una corrispondenza e sono entrambi associati nell’ambito cercato. Non è possibile riprovare con la stessa acquisizione. |
SCAN_SEARCH_INCOMPLETE | 503 | Alcune partizioni hanno risposto “nessuna corrispondenza”, ma non è stato possibile cercare nelle altre. Non si tratta di una mancata corrispondenza: riprova. |
SCAN_LOW_KEYPOINTS / SCAN_NO_KEYPOINTS | 400 | L’acquisizione stessa è stata rifiutata: contiene troppo pochi dettagli utilizzabili. Esegui una nuova scansione; non riprovare con la stessa immagine. |
SCAN_IDENTICAL_SCAN | 400 | I byte dell’immagine inviata sono identici a quelli di un’acquisizione precedente. Acquisiscine una nuova. |
SCAN_EXTRACTION_FAILURE | 500 | L’estrazione non è riuscita su un’immagine che era stata altrimenti accettata. |
SCAN_ROUTING_UNAVAILABLE | 503 | L’operazione non è disponibile per questa organizzazione (per esempio, un modulo non abilitato) oppure il relativo percorso non è disponibile. |
SCAN_BACKEND_UNAVAILABLE | 503 | Il backend di scansione è temporaneamente non disponibile. L’acquisizione è valida: riprova, non eseguire una nuova scansione. |
Esiti canonici dell’identificazione
Sezione intitolata “Esiti canonici dell’identificazione”POST /api/v1/tags/identify ha otto esiti. Tre restituiscono 200; gli altri vengono restituiti con stati di errore, ma sono comunque risposte. Questa tabella è l’unica fonte di riferimento sia per le integrazioni umane sia per quelle basate su agenti: la stessa tabella compare nelle skill dice-api-integration e dust-go-connect-integration.
| Esito | HTTP | Corpo | Significato | Cosa fare |
|---|---|---|---|---|
| Scheda identificata | 200 | { type: "identified", identified: { tag, thread, … }, scan? } | È stata trovata esattamente una corrispondenza con un identificatore associato. | Apri la Scheda. scan.dustId è il DUST risolto. |
| Più candidati | 200 | { type: "matches", matches: [ … ], scan? } | È stata trovata una corrispondenza con più di un identificatore associato oppure la corrispondenza deve essere disambiguata. | Mostra i candidati ed esegui nuovamente l’identificazione tramite tagId (tagType: "ANY"). scan.dustId è null; ogni candidato include il proprio valore. |
| Etichetta non associata | 200 | { type: "label", label: { label, tags }, scan? } | La scansione è stata ricondotta a un elemento di un’etichetta nell’inventario del tuo Team che non è ancora associata ad alcuna Scheda. | Proponi di associare l’etichetta. Non è una mancata corrispondenza. |
| Nessuna corrispondenza | 404 | code: "IDENTIFIER_NOT_FOUND", detail.outcome: "no_match" | Ogni partizione interrogata ha risposto e non è stata trovata alcuna corrispondenza. detail.teamsSearched indica l’ambito. | Mostra “non trovato”. Non segnalare un errore del servizio. La ricevuta si trova in detail.scan. |
| Ricerca incompleta | 503 | code: "SCAN_SEARCH_INCOMPLETE", detail.outcome: "search_incomplete" | Alcune partizioni hanno risposto “nessuna corrispondenza”, mentre le altre non erano raggiungibili. detail.teamsSearched, detail.teamsUnreachable, detail.orgsUnreachable. | Riprova. Non rappresentare mai questo esito come “non trovato”: l’oggetto potrebbe benissimo essere registrato. |
| Corrispondenza ambigua | 409 | code: "SCAN_AMBIGUOUS_MATCH", detail.outcome: "ambiguous", detail.candidates, detail.boundCandidates, detail.attempts | È stata trovata con sicurezza una corrispondenza con due o più DUST associati. La piattaforma ha cercato due volte usando la stessa acquisizione prima di restituire questo esito. | Mostra l’esito insieme a scan.scanId e contatta DUST Identity. Una nuova acquisizione dello stesso oggetto non risolverà l’ambiguità. |
| Acquisizione rifiutata | 400 | code: "SCAN_LOW_KEYPOINTS" / "SCAN_NO_KEYPOINTS" / "SCAN_IDENTICAL_SCAN", detail.outcome: "quality_reject" | Non è stato possibile utilizzare l’immagine. Il rifiuto per motivi di qualità ha la precedenza su qualsiasi altro esito delle partizioni. | Chiedi all’operatore di eseguire una nuova scansione. L’immagine viene conservata come scansione rifiutata; detail.scan.fingerprintId è null. |
| Identificatore non associato | 404 | code: "IDENTIFIER_NOT_BOUND" | Solo in caso di identificazione tramite tagId (tagType: "ANY"): l’identificatore esiste ma non è associato ad alcuna Scheda. | Proponi di associarlo. |
detail.outcome è la classificazione utilizzata dal server ed è stabile: no_match, search_incomplete, ambiguous, quality_reject. Crea prima una diramazione in base a code, quindi leggi detail.outcome quando hai bisogno della distinzione più specifica.
Diramazione in base al risultato di un’identificazione
Sezione intitolata “Diramazione in base al risultato di un’identificazione”// Runs on your SERVER (it holds the bearer token).const response = await fetch(`${apidUrl}/api/v1/tags/identify`, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Dust-Ctx-Org-Id": organizationId }, body: form,});const body = await response.json();
if (response.ok) { switch (body.type) { case "identified": return { kind: "thread", thread: body.identified.thread }; case "matches": return { kind: "candidates", candidates: body.matches }; case "label": return { kind: "unbound-label", label: body.label }; default: throw new Error(`Unknown identify result type: ${body.type}`); }}
switch (body.code) { case "IDENTIFIER_NOT_FOUND": // An answer, not an outage. return { kind: "no-match", scanId: body.detail?.scan?.scanId ?? null }; case "SCAN_SEARCH_INCOMPLETE": case "SCAN_BACKEND_UNAVAILABLE": return { kind: "retry", scanId: body.detail?.scan?.scanId ?? null }; case "SCAN_LOW_KEYPOINTS": case "SCAN_NO_KEYPOINTS": case "SCAN_IDENTICAL_SCAN": return { kind: "rescan", scanId: body.detail?.scan?.scanId ?? null }; case "SCAN_AMBIGUOUS_MATCH": return { kind: "ambiguous", scanId: body.detail?.scan?.scanId ?? null }; default: throw new Error(`${body.code}: ${body.message}`);}Esiti della verifica
Sezione intitolata “Esiti della verifica”POST /api/v1/tags/verify si comporta in modo diverso in base al numero di identificatori candidati inviati in tags, perché un solo candidato rappresenta una domanda sì/no, mentre più candidati costituiscono una ricerca:
Lunghezza di tags | Corrispondenza | Nessuna corrispondenza |
|---|---|---|
| Esattamente uno | 200 con { tag, scan? } | IDENTIFIER_VERIFY_FAILED (500), ricevuta in detail.scan |
| Due o più | 200 con { success: true, verifiedTag, attemptedCount, failedCount, scan? } | 200 con { success: false, attemptedCount, failedCount, error, scan? } |
Pertanto, una verifica in blocco non riuscita è una chiamata HTTP riuscita con success: false. Quando invii più di un candidato, leggi sempre success e non dedurre mai l’autenticità dal solo valore di response.ok.
tags è obbligatorio in ogni verifica. È un array di oggetti, non di ID:
[{ "tagId": "8f2b…", "tagType": "DUST" }]Le ricevute di scansione vengono conservate anche in caso di errore
Sezione intitolata “Le ricevute di scansione vengono conservate anche in caso di errore”Ogni operazione che invia un’immagine — estrazione, associazione, identificazione, verifica, analisi delle alterazioni — restituisce una ricevuta di scansione che indica ciò che è stato archiviato:
{ "scanId": "…", "fingerprintId": "…", "dustId": "…" }- In caso di riuscita, si trova al livello principale come
scan. - In caso di esito negativo ma archiviato, si trova in
detail.scan: una mancata corrispondenza della verifica, un’identificazione senza corrispondenze, un’associazione rifiutata perché duplicata e un rifiuto per motivi di qualità (nel qualefingerprintIdènull, perché non è stato estratto nulla di utilizzabile).
Acquisisci scanId in entrambi i casi. È l’identità stabile dell’acquisizione durante le migrazioni degli algoritmi ed è ciò che serve all’assistenza per esaminare l’immagine alla base di un risultato contestato. Soltanto un’immagine che la piattaforma non è riuscita affatto a decodificare non archivia nulla; in quel caso non è presente alcuna ricevuta.
const receipt = response.ok ? body.scan : body.detail?.scan;if (receipt) await recordScan(receipt.scanId, receipt.fingerprintId, receipt.dustId);dustId rappresenta ciò che la piattaforma ha restituito all’utente, mai una corrispondenza interna non elaborata: è null in caso di mancata corrispondenza, nessuna corrispondenza, estrazione, analisi delle alterazioni e identificazione che ha restituito più candidati.
Scadenza e rinnovo dei token
Sezione intitolata “Scadenza e rinnovo dei token”I token bearer hanno una durata breve e non esiste un token di aggiornamento: devi effettuare nuovamente lo scambio delle credenziali. Un token scaduto produce un normale 401 UNAUTHORIZED, indistinguibile da quello di un token revocato, quindi gestisci entrambi allo stesso modo:
- Rinnova in modo proattivo.
GET /api/auth/tokenrestituisceexpiresIn(secondi) eexpiresAt(ISO 8601) ogni volta che il token include un’indicazione di scadenza. Effettua nuovamente lo scambio con un certo margine (60 secondi sono sufficienti); non codificare mai una durata fissa. - Riprova una volta in caso di
401. Sia la differenza tra gli orologi sia una revoca durante il periodo di validità producono questo esito. Un rinnovo seguito da un solo nuovo tentativo è sufficiente; un ciclo non lo è. - Genera un token per ogni richiesta utilizzando una cache, non una sola volta all’avvio del processo, affinché un processo che dura più a lungo di un token non si interrompa a metà.
L’implementazione completa si trova in Autenticazione → Scadenza e rinnovo dei token.
Indicazioni sui nuovi tentativi
Sezione intitolata “Indicazioni sui nuovi tentativi”| Situazione | Riprovare la stessa richiesta? | Note |
|---|---|---|
401 UNAUTHORIZED | Sì, una volta, dopo aver effettuato nuovamente lo scambio delle credenziali | Più di un tentativo indica che la credenziale stessa è errata. |
429 RATE_LIMITED | Sì, con backoff | |
503 SCAN_SEARCH_INCOMPLETE / SCAN_BACKEND_UNAVAILABLE | Sì: l’acquisizione è valida | Non chiedere all’operatore di eseguire una nuova scansione. |
503 SCAN_ROUTING_UNAVAILABLE | No | L’operazione non è disponibile per questa organizzazione; contatta DUST Identity. |
400 SCAN_LOW_KEYPOINTS / SCAN_NO_KEYPOINTS / SCAN_IDENTICAL_SCAN | No: esegui invece una nuova scansione | Gli stessi byte verranno nuovamente rifiutati. |
404 IDENTIFIER_NOT_FOUND | No | È una risposta. |
409 SCAN_AMBIGUOUS_MATCH | No | Il server ha già effettuato un nuovo tentativo; detail.attempts lo indica. |
409 THREAD_DATA_CONFLICT | Leggi di nuovo, riapplica le modifiche, quindi scrivi | Non riprovare alla cieca: sovrascriveresti le modifiche di qualcun altro. |
5xx UNKNOWN_ERROR | Sì, con backoff, per le letture idempotenti | Per le scritture, verifica che siano state applicate prima di riprovare. |
Vedi anche
Sezione intitolata “Vedi anche”- Convenzioni delle richieste — intestazioni, paginazione, localizzazione.
- Identificatori — le operazioni di scansione da cui derivano questi esiti.
- Autenticazione e chiavi API — credenziali e durata dei token.
- Riferimento API — schemi delle risposte specifici per ciascun endpoint.