Przejdź do głównej zawartości

Błędy i wyniki skanowania

To strona referencyjna dotycząca obsługi błędów: treść błędu zwracana przez każdy punkt końcowy, kody, od których warto uzależniać logikę, oraz — co najważniejsze — kanoniczne tabele wyników skanowania. „Brak dopasowania” to wynik, a nie błąd transportu, mimo że przychodzi z kodem stanu błędu HTTP. Kod, który traktuje każdą odpowiedź spoza zakresu 2xx jako usterkę, będzie zgłaszać awarie, które nigdy nie wystąpiły.

Schematy poszczególnych punktów końcowych znajdują się w dokumentacji API. Same przepływy opisano w sekcjach Identyfikatory i Szybki start.

Każde nieudane żądanie zwraca ten sam obiekt 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 } }
}
PoleTypZnaczenie
codestringStały kod czytelny dla maszyn. Od niego uzależniaj logikę. Nigdy nie analizuj message.
messagestringTekst czytelny dla człowieka, zlokalizowany zgodnie z Dust-Ctx-Locale. Sformułowania się zmieniają; kody nie.
statusnumberOdzwierciedla kod stanu HTTP.
detailobject, opcjonalneKontekst konkretnego błędu: szczegóły walidacji, raport skanu, klasyfikacja wyniku, ID konfliktów.

status i kod stanu HTTP są zawsze zgodne, więc logikę można uzależnić od dowolnego z nich. Każda odpowiedź — pomyślna lub nie — zawiera też nagłówek x-request-id. Zapisuj go w logach; zespół wsparcia używa go, aby odnaleźć dokładnie twoje żądanie.

KodStatusKiedy
INVALID_REQUEST400Nieprawidłowa treść, zapytanie lub nagłówek. Szczegóły walidacji w detail.
INVALID_DATA400Żądanie zostało przeanalizowane, ale wartości nie można użyć (na przykład ładunek identyfikacji, którego usługa skanowania odmówiła odczytania).
UNAUTHORIZED401Brakujący, wygasły lub nieprawidłowy token Bearer.
FORBIDDEN403Uwierzytelniono, ale ten kontekst nie może wykonać tej operacji.
ATTRIBUTION_REQUIRED403Zasady przypisania konta usługi mają wartość required, a zapis nie zawierał nagłówka Dust-Ctx-Declared-Actor.
ORG_ID_REQUIRED / TEAM_ID_REQUIRED400W punkcie końcowym o określonym zakresie brakuje nagłówka kontekstu.
NOT_FOUND / NO_DATA_FOUND404Żaden taki obiekt nie jest widoczny w tym kontekście.
RATE_LIMITED429Odczekaj i ponów próbę.
THREAD_DATA_CONFLICT409Konflikt współbieżności optymistycznej: twoja wartość expectedUpdatedAt jest nieaktualna. Odczytaj dane ponownie i zastosuj zmiany jeszcze raz.
COMPOSITE_TAG_CONFLICT409Konflikt etykiety — DUST znajduje się już na innej etykiecie lub jest powiązany gdzie indziej, pozycja na rolce jest zajęta albo usuwany jest ostatni identyfikator etykiety. detail.reason wskazuje, który przypadek zaszedł.
UNKNOWN_ERROR / SERVICE_ERROR500Błąd po stronie serwera. Ponów próbę z wydłużającym się odstępem; jeśli problem się utrzymuje, podaj ID żądania.
KodStatusZnaczenie
IDENTIFIER_NOT_FOUND404Ostateczny brak dopasowania: odpowiedziała każda przeszukiwana partycja i nic nie zostało dopasowane.
IDENTIFIER_NOT_BOUND404Identyfikator istnieje, ale nie jest powiązany z żadnym rekordem (osiągalne tylko przez identyfikację według tagId).
IDENTIFIER_ALREADY_BOUND409Odmowa powiązania — ten identyfikator (lub jego etykieta) znajduje się już w innym rekordzie. detail.compositeTagId wskazuje etykietę.
IDENTIFIER_VERIFY_FAILED500Weryfikacja pojedynczego identyfikatora nie dała dopasowania albo wskazany identyfikator nie jest powiązany z tym rekordem.
SCAN_AMBIGUOUS_MATCH409Dopasowano dwa lub więcej różnych zarejestrowanych DUST i wszystkie są powiązane w przeszukiwanym zakresie. Ponowienie z tym samym ujęciem nic nie da.
SCAN_SEARCH_INCOMPLETE503Część partycji odpowiedziała „brak dopasowania”, ale innych nie udało się przeszukać. To nie jest brak dopasowania — ponów próbę.
SCAN_LOW_KEYPOINTS / SCAN_NO_KEYPOINTS400Samo ujęcie zostało odrzucone: zbyt mało użytecznych szczegółów. Zeskanuj ponownie; nie ponawiaj z tym samym obrazem.
SCAN_IDENTICAL_SCAN400Przesłany obraz ma bajty identyczne z wcześniejszym ujęciem. Wykonaj nowe.
SCAN_EXTRACTION_FAILURE500Ekstrakcja nie powiodła się dla obrazu, który poza tym został zaakceptowany.
SCAN_ROUTING_UNAVAILABLE503Operacja nie jest dostępna dla tej organizacji (na przykład moduł nie jest włączony) albo jej trasa nie działa.
SCAN_BACKEND_UNAVAILABLE503Zaplecze skanowania jest tymczasowo niedostępne. Ujęcie było w porządku — ponów próbę, nie skanuj ponownie.

POST /api/v1/tags/identify ma osiem wyników. Trzy mają kod 200; pozostałe przychodzą z kodami stanu błędu i mimo to są odpowiedziami. Ta tabela jest jedynym źródłem zarówno dla integracji tworzonych przez ludzi, jak i przez agentów — ta sama tabela występuje w umiejętnościach dice-api-integration i dust-go-connect-integration.

WynikHTTPTreśćCo oznaczaCo zrobić
Zidentyfikowany rekord200{ type: "identified", identified: { tag, thread, … }, scan? }Dopasowano dokładnie jeden powiązany identyfikator.Otwórz rekord. scan.dustId to rozpoznany DUST.
Kilku kandydatów200{ type: "matches", matches: [ … ], scan? }Dopasowano więcej niż jeden powiązany identyfikator albo dopasowanie wymaga rozstrzygnięcia.Pokaż kandydatów i ponownie wykonaj identyfikację według tagId (tagType: "ANY"). scan.dustId ma wartość null; każdy kandydat zawiera własną wartość.
Niepowiązana etykieta200{ type: "label", label: { label, tags }, scan? }Skan wskazał identyfikator należący do etykiety z zasobów twojego zespołu, która nie jest jeszcze powiązana z żadnym rekordem.Zaproponuj powiązanie etykiety. To nie jest brak dopasowania.
Brak dopasowania404code: "IDENTIFIER_NOT_FOUND", detail.outcome: "no_match"Odpowiedziała każda przeszukiwana partycja i nic nie zostało dopasowane. detail.teamsSearched podaje zakres.Pokaż „nie znaleziono”. Nie zgłaszaj awarii usługi. Raport skanu w detail.scan.
Niepełne wyszukiwanie503code: "SCAN_SEARCH_INCOMPLETE", detail.outcome: "search_incomplete"Część partycji odpowiedziała „brak dopasowania”, a z innymi nie udało się połączyć. detail.teamsSearched, detail.teamsUnreachable, detail.orgsUnreachable.Ponów próbę. Nigdy nie przedstawiaj tego jako „nie znaleziono” — przedmiot może być zarejestrowany.
Niejednoznaczne dopasowanie409code: "SCAN_AMBIGUOUS_MATCH", detail.outcome: "ambiguous", detail.candidates, detail.boundCandidates, detail.attemptsZ dużą pewnością dopasowano dwa lub więcej powiązanych DUST. Platforma dwukrotnie przeszukała to samo ujęcie, zanim zwróciła ten wynik.Przekaż ten wynik wraz z scan.scanId i skontaktuj się z DUST Identity. Nowe ujęcie tego samego przedmiotu tego nie rozstrzygnie.
Odrzucone ujęcie400code: "SCAN_LOW_KEYPOINTS" / "SCAN_NO_KEYPOINTS" / "SCAN_IDENTICAL_SCAN", detail.outcome: "quality_reject"Nie można było użyć obrazu. Odrzucenie ze względu na jakość ma pierwszeństwo przed wszystkimi innymi wynikami partycji.Poproś operatora o ponowne zeskanowanie. Obraz jest zachowywany jako odrzucony skan; detail.scan.fingerprintId ma wartość null.
Identyfikator niepowiązany404code: "IDENTIFIER_NOT_BOUND"Tylko przy identyfikacji według tagId (tagType: "ANY"): identyfikator istnieje, ale nie ma rekordu.Zaproponuj jego powiązanie.

detail.outcome to klasyfikacja użyta przez serwer; jej wartości są stałe: no_match, search_incomplete, ambiguous, quality_reject. Najpierw uzależniaj logikę od code, a detail.outcome odczytuj, gdy potrzebujesz dokładniejszego rozróżnienia.

Rozgałęzianie logiki na podstawie wyniku identyfikacji

Dział zatytułowany „Rozgałęzianie logiki na podstawie wyniku identyfikacji”
// 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}`);
}

POST /api/v1/tags/verify działa różnie w zależności od tego, ilu identyfikatorów kandydujących przesyłasz w tags, ponieważ jeden kandydat to pytanie typu tak/nie, a kilku to wyszukiwanie:

Długość tagsDopasowanieBrak dopasowania
Dokładnie jeden200 z { tag, scan? }IDENTIFIER_VERIFY_FAILED (500), raport skanu w detail.scan
Dwa lub więcej200 z { success: true, verifiedTag, attemptedCount, failedCount, scan? }200 z { success: false, attemptedCount, failedCount, error, scan? }

Zbiorcza weryfikacja, która się nie powiedzie, jest więc pomyślnym wywołaniem HTTP z success: false. Zawsze odczytuj success, gdy przesyłasz więcej niż jednego kandydata, i nigdy nie wnioskuj o autentyczności na podstawie samego response.ok.

Pole tags jest wymagane przy każdej weryfikacji. Jest to tablica obiektów, a nie samych wartości ID:

[{ "tagId": "8f2b…", "tagType": "DUST" }]

Każda operacja przesyłająca obraz — ekstrakcja, powiązanie, identyfikacja, weryfikacja, analiza manipulacji — zwraca raport skanu wskazujący, co zostało zapisane:

{ "scanId": "…", "fingerprintId": "…", "dustId": "…" }
  • W przypadku powodzenia znajduje się na najwyższym poziomie jako scan.
  • W przypadku wyniku zapisanego, ale negatywnego, znajduje się w detail.scan — dotyczy to niezgodności przy weryfikacji, braku dopasowania przy identyfikacji, odmowy powiązania z powodu duplikatu oraz odrzucenia ze względu na jakość (wtedy fingerprintId ma wartość null, ponieważ nie wyodrębniono nic użytecznego).

Zapisuj scanId w obu przypadkach. Jest to stała tożsamość ujęcia, niezmienna przy migracjach algorytmów, i właśnie jej potrzebuje zespół wsparcia, aby obejrzeć obraz stojący za spornym wynikiem. Tylko obraz, którego platforma w ogóle nie mogła zdekodować, nie jest zapisywany — wtedy raportu skanu nie ma.

const receipt = response.ok ? body.scan : body.detail?.scan;
if (receipt) await recordScan(receipt.scanId, receipt.fingerprintId, receipt.dustId);

dustId to wartość, którą platforma ci zwróciła, a nigdy surowe wewnętrzne dopasowanie: ma wartość null przy niezgodności, braku dopasowania, ekstrakcji, analizie manipulacji oraz przy identyfikacji, która zwróciła kilku kandydatów.

Tokeny Bearer są krótkotrwałe i nie ma tokenu odświeżania — poświadczenie wymienia się ponownie. Wygasły token powoduje zwykły błąd 401 UNAUTHORIZED, nieodróżnialny od tokenu unieważnionego, więc oba przypadki obsługuj tak samo:

  1. Odświeżaj z wyprzedzeniem. GET /api/auth/token zwraca expiresIn (w sekundach) i expiresAt (ISO 8601), gdy token zawiera oświadczenie o wygaśnięciu. Wymieniaj poświadczenie ponownie z zapasem (60 sekund to wygodna wartość); nigdy nie koduj czasu życia na sztywno.
  2. Po błędzie 401 ponów próbę jeden raz. Trafiają tu zarówno rozbieżności zegarów, jak i unieważnienie w trakcie ważności tokenu. Jedno odświeżenie i ponowienie to właściwa liczba; pętla już nie.
  3. Pobieraj token dla każdego żądania z pamięci podręcznej, a nie raz przy uruchomieniu procesu, aby zadanie trwające dłużej niż ważność jednego tokenu nie przerwało się w połowie.

Gotowa implementacja znajduje się w sekcji Uwierzytelnianie → Wygasanie i odświeżanie tokenów.

SytuacjaPonowić to samo żądanie?Uwagi
401 UNAUTHORIZEDTak, jeden raz, po ponownej wymianie poświadczeniaKolejny błąd oznacza, że nieprawidłowe jest samo poświadczenie.
429 RATE_LIMITEDTak, z wydłużającym się odstępem
503 SCAN_SEARCH_INCOMPLETE / SCAN_BACKEND_UNAVAILABLETak — ujęcie jest w porządkuNie każ operatorowi skanować ponownie.
503 SCAN_ROUTING_UNAVAILABLENieOperacja jest niedostępna dla tej organizacji; skontaktuj się z DUST Identity.
400 SCAN_LOW_KEYPOINTS / SCAN_NO_KEYPOINTS / SCAN_IDENTICAL_SCANNie — zamiast tego zeskanuj ponownieTe same bajty zostaną ponownie odrzucone.
404 IDENTIFIER_NOT_FOUNDNieTo jest odpowiedź.
409 SCAN_AMBIGUOUS_MATCHNiePonowiono już po stronie serwera; informuje o tym detail.attempts.
409 THREAD_DATA_CONFLICTOdczytaj ponownie, zastosuj zmiany jeszcze raz, a następnie zapiszNie ponawiaj na ślepo — mogłoby to nadpisać czyjeś zmiany.
5xx UNKNOWN_ERRORTak, z wydłużającym się odstępem, w przypadku idempotentnych odczytówW przypadku zapisów przed ponowieniem sprawdź, czy zapis został wykonany.