> ## Documentation Index
> Fetch the complete documentation index at: https://developer.suki.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> Search or browse troubleshooting guides for common Suki API and SDK issues

export const tsUtil = {
  empty: {
    q: "",
    topic: "all",
    products: [],
    codes: []
  },
  safe: (fn, fallback) => {
    try {
      return fn();
    } catch (e) {
      return fallback;
    }
  },
  readQuery: () => tsUtil.safe(() => new URLSearchParams(window.location.search), new URLSearchParams()),
  writeQuery: sp => tsUtil.safe(() => {
    if (!(/^https?:$/).test(window.location.protocol)) return;
    const qs = sp.toString();
    window.history.replaceState(window.history.state, "", window.location.pathname + (qs ? `?${qs}` : "") + window.location.hash);
  }),
  store: {
    s: {
      q: "",
      topic: "all",
      products: [],
      codes: [],
      rows: null
    },
    l: new Set()
  },
  setStore: patch => {
    const st = tsUtil.store;
    st.s = {
      ...st.s,
      ...patch
    };
    st.l.forEach(f => f(st.s));
  },
  useStore: () => {
    const [s, set] = useState(tsUtil.store.s);
    useEffect(() => {
      const st = tsUtil.store;
      st.l.add(set);
      set(st.s);
      return () => {
        st.l.delete(set);
      };
    }, []);
    return s;
  },
  toggleIn: (key, id) => {
    const cur = tsUtil.store.s[key];
    tsUtil.setStore({
      [key]: cur.includes(id) ? cur.filter(x => x !== id) : [...cur, id]
    });
  },
  clearAll: () => tsUtil.setStore({
    ...tsUtil.empty
  }),
  sp: s => String(s || "").split(/[\s,]+/).filter(Boolean),
  camel: s => String(s).replace(/([a-z0-9])([A-Z])/g, "$1 $2"),
  fold: s => ` ${String(s).toLowerCase().replace(/[^a-z0-9]+/g, " ")} `,
  hayOf: s => tsUtil.fold(`${s} ${tsUtil.camel(s)}`),
  words: q => tsUtil.fold(tsUtil.camel(q)).trim().split(" ").filter(Boolean),
  hasWords: (hay, ws) => ws.every(w => hay.includes(` ${w}`)),
  plural: (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`,
  label: (list, id) => (list.find(x => x.id === id) || ({
    label: id
  })).label,
  isStatus: c => (/^\d{3}$/).test(c),
  isRow: n => !!(n && typeof n === "object" && n.props && (n.type === TsHubRow || n.props.href && n.props.title && ("error" in n.props))),
  collectRows: (node, out) => {
    if (Array.isArray(node)) {
      node.forEach(n => tsUtil.collectRows(n, out));
      return out;
    }
    if (!node || typeof node !== "object" || !node.props) return out;
    if (tsUtil.isRow(node)) {
      out.push(node.props);
      return out;
    }
    return tsUtil.collectRows(node.props.children, out);
  },
  toModel: (p, i) => {
    const u = tsUtil;
    const parts = String(p.code || "").split("·").map(x => x.trim()).filter(Boolean);
    const status = parts.find(u.isStatus) || null;
    const errors = [];
    [...parts, ...u.sp(p.error)].forEach(e => {
      if (!errors.some(x => x.toLowerCase() === e.toLowerCase())) errors.push(e);
    });
    const topic = u.sp(p.tags)[0] || "other";
    const shown = u.sp(p.products);
    const prodSet = Array.from(new Set([...shown, ...u.sp(p.product)]));
    return {
      i,
      href: p.href,
      title: p.title,
      status,
      chips: parts.filter(x => !u.isStatus(x)),
      errors,
      topic,
      shown,
      prodSet,
      hay: u.hayOf([p.title, p.code, p.error, p.search, p.tags, shown.map(x => u.label(TS.products, x)).join(" ")].join(" ")),
      codeHay: [p.code, p.error, p.search].join(" ").toLowerCase()
    };
  },
  hasCode: (r, id) => r.errors.some(e => e.toLowerCase() === id) || r.codeHay.includes(id),
  topicsFor: rows => {
    const out = [...TS.topics];
    rows.forEach(r => {
      if (!out.some(t => t.id === r.topic)) out.push({
        id: r.topic,
        label: r.topic.replace(/-/g, " "),
        icon: "layers"
      });
    });
    return out;
  },
  codeIndex: rows => {
    const map = new Map();
    rows.forEach(r => r.errors.forEach(e => {
      const k = e.toLowerCase();
      if (!map.has(k)) map.set(k, e);
    }));
    TS.errorCodes.forEach(e => {
      const k = e.toLowerCase();
      if (!map.has(k)) map.set(k, e);
    });
    return [...map.entries()].map(([id, lbl]) => ({
      id,
      label: lbl,
      status: tsUtil.isStatus(id)
    })).sort((a, b) => a.status !== b.status ? a.status ? -1 : 1 : a.label.localeCompare(b.label, "en", {
      sensitivity: "base"
    }));
  },
  matches: (r, s, skip) => (skip === "topic" || s.topic === "all" || r.topic === s.topic) && (skip === "products" || !s.products.length || r.prodSet.some(p => s.products.includes(p))) && (skip === "codes" || !s.codes.length || s.codes.some(c => tsUtil.hasCode(r, c))) && tsUtil.hasWords(r.hay, tsUtil.words(s.q)),
  filtering: s => !!s.q.trim() || s.topic !== "all" || s.products.length > 0 || s.codes.length > 0,
  esc: s => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
  Hl: ({text, ws}) => {
    if (!ws.length || typeof text !== "string") return text;
    const parts = tsUtil.safe(() => text.split(new RegExp(`(?<![a-z0-9])(${ws.map(tsUtil.esc).join("|")})`, "ig")), [text]);
    return <>{parts.map((p, i) => i % 2 ? <mark key={i}>{p}</mark> : p)}</>;
  },
  tone: status => !status ? "plain" : (/^40[13]$/).test(status) ? "yellow" : (/^5/).test(status) ? "red" : "blue"
};

export const TsIcon = ({k, size = 16, sw = 1.6}) => <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className={`sts-ic sts-ic-${k}`}><path d={TS.paths[k]} /></svg>;

export const TsProductTags = ({products, shown}) => <span className="sts-prods">{(shown || tsUtil.sp(products)).map(p => <span key={p} className="sts-ptag">{tsUtil.label(TS.products, p)}</span>)}</span>;

export const TsRow = ({r, ws, codes, topics}) => {
  const u = tsUtil;
  const t = topics.find(x => x.id === r.topic) || ({
    icon: "layers",
    label: r.topic
  });
  const visible = new Set([r.status, ...r.chips].filter(Boolean).map(x => x.toLowerCase()));
  const also = r.errors.filter(e => !visible.has(e.toLowerCase()) && (codes.includes(e.toLowerCase()) || ws.length && ws.some(w => u.hayOf(e).includes(` ${w}`)))).slice(0, 3);
  const related = !r.status && !r.chips.length ? r.errors.slice(0, 3) : [];
  return <li>
      <a className="sts-row" href={r.href}>
        <span className={`sts-tile sts-tile-${u.tone(r.status)}`} aria-hidden={r.status ? undefined : "true"}>
          {r.status ? <b><u.Hl text={r.status} ws={ws} /></b> : <TsIcon k={t.icon} size={20} />}
        </span>
        <span className="sts-main">
          <span className="sts-title"><u.Hl text={r.title} ws={ws} /></span>
          {(r.chips.length > 0 || also.length > 0 || related.length > 0) && <span className="sts-codes">
              {r.chips.map(c => <code key={c}><u.Hl text={c} ws={ws} /></code>)}
              {related.length > 0 && !also.length && <span className="sts-rel">Related: {related.map(c => <code key={c}>{c}</code>)}</span>}
              {also.length > 0 && <span className="sts-rel sts-rel-hit">Also covers {also.map(c => <code key={c}><u.Hl text={c} ws={ws} /></code>)}</span>}
            </span>}
        </span>
        <TsProductTags shown={r.shown} />
        <span className="sts-go"><TsIcon k="arrow" size={16} sw={1.5} /></span>
      </a>
    </li>;
};

export const TsHubList = ({children}) => {
  const u = tsUtil;
  const s = u.useStore();
  const rows = u.collectRows(children, []).map(u.toModel);
  const key = rows.map(r => r.href).join("|");
  useEffect(() => {
    u.setStore({
      rows
    });
  }, [key]);
  const topics = u.topicsFor(rows);
  const ws = u.words(s.q);
  const shown = rows.filter(r => u.matches(r, s));
  const groups = topics.map(t => ({
    t,
    items: shown.filter(r => r.topic === t.id)
  })).filter(g => g.items.length);
  return <div className="sts sts-list">
      {groups.map(g => <section key={g.t.id} className="sts-group" aria-labelledby={`sts-g-${g.t.id}`}>
          <h2 className="sts-group-h" id={`sts-g-${g.t.id}`}><span className="sts-kicker">{g.t.label}</span><span className="sts-group-n">{u.plural(g.items.length, "guide")}</span></h2>
          <ul className="sts-rows">{g.items.map(r => <TsRow key={r.href} r={r} ws={ws} codes={s.codes} topics={topics} />)}</ul>
        </section>)}
    </div>;
};

export const TsHubRow = props => {
  const r = tsUtil.toModel(props, 0);
  return <ul className="sts sts-rows"><TsRow r={r} ws={[]} codes={[]} topics={TS.topics} /></ul>;
};

export const TS = {
  kicker: "Resources",
  products: [{
    id: "authentication",
    label: "Authentication"
  }, {
    id: "ambient",
    label: "Ambient"
  }, {
    id: "dictation",
    label: "Dictation"
  }, {
    id: "form-filling",
    label: "Form Filling"
  }, {
    id: "web-sdk",
    label: "Web SDK"
  }, {
    id: "mobile-sdk",
    label: "Mobile SDK"
  }, {
    id: "headless-web-sdk",
    label: "Headless Web SDK"
  }, {
    id: "webhooks",
    label: "Webhooks"
  }, {
    id: "streaming",
    label: "Streaming"
  }, {
    id: "apis",
    label: "APIs"
  }, {
    id: "patient-summary",
    label: "Patient Summary"
  }],
  topics: [{
    id: "auth",
    label: "Auth",
    icon: "key"
  }, {
    id: "sessions",
    label: "Sessions",
    icon: "layers"
  }, {
    id: "streaming",
    label: "Streaming",
    icon: "wave"
  }, {
    id: "microphone",
    label: "Microphone",
    icon: "mic"
  }, {
    id: "offline",
    label: "Offline",
    icon: "cloud"
  }, {
    id: "csp",
    label: "CSP",
    icon: "shield"
  }, {
    id: "webhooks",
    label: "Webhooks",
    icon: "hook"
  }, {
    id: "platform",
    label: "Platform",
    icon: "server"
  }],
  support: {
    label: "Email Technical Support",
    href: "mailto:support@suki.ai"
  },
  catalogs: [{
    label: "Ambient & Dictation",
    href: "/api-reference/error-messages"
  }, {
    label: "Form filling",
    href: "/form-filling-api-reference/error-messages-form-filling"
  }, {
    label: "Patient Summary",
    href: "/patient-summary-api-reference/error-messages-patient-summary"
  }, {
    label: "Mobile SDK",
    href: "/mobile-sdk/error-messages"
  }],
  errorCodes: ["400", "401", "403", "404", "409", "412", "499", "500", "501", "503", "504", "Aborted", "AlreadyExists", "ambient_session_id_required", "ambient_session_not_found", "appIsNotActive", "AudioRecorderFailure", "Canceled", "cancelRemoteSessionFailed", "client_disconnected", "client_metrics_log_failed", "comments_too_long", "content_retention_exceeded", "content_rewrite_not_enabled", "CSP", "DeadlineExceeded", "encounter_content_retention_exceeded", "encounter_structured_data_retention_exceeded", "endRemoteSessionFailed", "error_adding_context", "ERROR_CODE_NOTIFICATION_GENERATION_FAILURE", "ERROR_CODE_TRANSCRIPTION", "ERROR_CODE_UNSPECIFIED", "error_creating_session", "error_creating_transcription_session", "error_creating_transcription_stream", "error_ending_session", "error_ending_transcription", "error_ending_transcription_session", "error_extracting_ambient_session_id", "error_extracting_transcription_session_id", "error_fetching_encounter_notes", "error_fetching_recording", "error_generating_presigned_url", "error_processing_context", "error_reading_transcripts", "error_receiving_audio", "error_resolving_encounter", "error_sending_audio", "error_streaming_audio", "error_updating_preferences", "failed_get_session", "FAILED_PRECONDITION", "failed_submit_feedback", "failed_to_generate_patient_summaries_for_fhir_practitioner", "failed_to_generate_patient_summary_for_fhir_encounter", "failed_to_get_enable_content_rewrite_config", "failed_to_get_fhir_patient_summary", "failed_to_get_fhir_pre_visit_summary", "failed_to_get_user_specialty", "failed_to_retrieve_partner", "FailedPrecondition", "feedback_metadata_nil", "feedback_required", "fhir_encounter_id_required", "fhir_pair_required", "fhir_practitioner_id_required", "form_filling_values_empty", "form_id_required", "form_metadata_invalid", "form_metadata_missing_ids", "form_metadata_read_failed", "form-filling:error", "getEncounterInfoFailed", "id_length_invalid", "insufficient_scope", "Internal", "internal_server_error", "invalid_ambient_id_format", "invalid_ambient_session_id", "INVALID_ARGUMENT", "invalid_cancel_session_request", "invalid_context_request", "invalid_encounter_id", "invalid_encryption_hash", "invalid_end_form_filling_session_request", "invalid_end_session_request", "invalid_entity", "invalid_form_template_id", "invalid_generate_patient_summary_request", "invalid_get_patient_summary_request", "invalid_get_patient_summary_status_request", "invalid_get_pre_visit_summary_request", "invalid_or_missing_partner_id", "invalid_organization_or_user_claims", "invalid_preferences_format", "invalid_rating_range", "invalid_request", "invalid_rewrite_content_request", "invalid_sdp_provider_id", "invalid_sdp_token", "invalid_section_format", "invalid_target_emr", "invalid_transcription_session_id", "invalid_transcription_session_id_format", "invalid_trigger_patient_summary_generation_request", "invalid_uuid_format", "invalid_verbosity", "InvalidArgument", "invalidBirthdate", "invalidContext", "invalidEncounterType", "invalidMedicationOrder", "InvalidPartnerDetails", "invalidPartnerId", "invalidPreferences", "invalidProviderDetails", "invalidProviderRole", "invalidSections", "InvalidSessionState", "invalidSpeciality", "invalidVisitType", "lookup_id_required", "medical_form_not_found", "micIsInUse", "missing_emr_encounter_id", "missing_organization_id", "missing_sdp_provider_id_header", "missing_user_id", "missingCodeFields", "missingDiagnosisCodes", "multiple_patient_summary_jobs_found", "needMicrophonePermissionRecording", "negative_min_rating", "NetworkOffline", "no_appointment_found", "no_patient_summary_job_found", "noSessionExist", "NotFound", "noValidDiagnosis", "OfflineSaveFailed", "onError", "patient_summary_lookup_id_conflict", "payload_required", "permission_denied", "PermissionDenied", "personalization_preference_required", "preference_required", "provider_not_registered", "provider_user_inactive", "rating_above_max", "rating_below_min", "rating_feedback_required", "remoteSessionConflict", "request_cancelled", "request_timeout", "ResumeSessionFailed", "sbac_denied", "SDKAlreadyInitilized", "SDKNotInitilized", "ServiceError", "session_in_progress", "session_job_type_unsupported", "session_not_form_filling", "session_wrong_state", "sessionAlreadyExists", "sessionInProgress", "StartSessionFailed", "StreamError", "structured_data_retention_exceeded", "SUKI_FF_001", "SUKI_FF_002", "SUKI_FF_003", "SUKI_FF_004", "template_id_required", "transcription_session_completed", "transcription_session_not_accepting", "transcription_session_not_found", "transcripts_retention_exceeded", "unableFetchContent", "unableFetchStructuredData", "unableFetchTranscript", "unableToStartRecording", "Unauthenticated", "Unavailable", "Unimplemented", "unknown_request_type", "update_paths_required", "UserNotFound", "verbosity_or_section_format_required"],
  paths: {
    key: "M7.5 8.5a3.5 3.5 0 1 0 0 7a3.5 3.5 0 1 0 0-7M11 12h9.5M17.5 12v3M20.5 12v2",
    layers: "M12 3.5l8.5 4.5-8.5 4.5L3.5 8zM3.5 12.5l8.5 4.5 8.5-4.5M3.5 16.5l8.5 4.5 8.5-4.5",
    wave: "M3 12h3.5l2.5-6 4 12 2.5-6H21",
    mic: "M9 6a3 3 0 0 1 6 0v6a3 3 0 0 1-6 0zM5.5 11.5a6.5 6.5 0 0 0 13 0M12 18v3",
    cloud: "M7 18.5h10a4 4 0 0 0 .6-8A6 6 0 0 0 6.2 9.5 4.5 4.5 0 0 0 7 18.5zM4 4l16 16",
    shield: "M12 3l7.5 3v5.5c0 4.5-3.2 8-7.5 9.5-4.3-1.5-7.5-5-7.5-9.5V6z",
    hook: "M7 4v9a5 5 0 0 0 10 0v-2M14 14l3-3 3 3",
    server: "M4 4h16v6H4zM4 14h16v6H4zM7.5 7h.5M7.5 17h.5",
    all: "M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z",
    search: "M10.5 4a6.5 6.5 0 1 0 0 13a6.5 6.5 0 1 0 0-13M15.5 15.5L20 20",
    chev: "M6 9l6 6 6-6",
    check: "M5 12.5l4.5 4.5L19 7",
    close: "M6 6l12 12M18 6L6 18",
    reset: "M4 12a8 8 0 1 0 2.3-5.7M4 4v4.5h4.5",
    arrow: "M4 12h16M14 6l6 6-6 6",
    mail: "M3.5 5.5h17v13h-17zM3.5 6.5l8.5 6.5 8.5-6.5"
  }
};

export const TsMsOption = ({id, label: text, selected, highlighted, count, mono, onPick, onHover}) => <li id={id} role="option" aria-selected={!!selected} data-hi={highlighted ? "" : undefined} data-zero={!count ? "" : undefined} onMouseEnter={onHover} onMouseDown={e => e.preventDefault()} onClick={onPick}>
    <span className="sts-box"><TsIcon k="check" size={12} sw={2.2} /></span>
    <span className={mono ? "sts-opt-lbl sts-mono" : "sts-opt-lbl"}>{text}</span>
    <span className="sts-opt-n">{count || 0}</span>
  </li>;

export const TsMenu = ({id, prefix, allLabel, options, selected, counts, onToggle, onClear, searchable, mono, note}) => {
  const u = tsUtil;
  const [open, setOpen] = useState(false);
  const [hi, setHi] = useState(0);
  const [q, setQ] = useState("");
  const wrap = useRef(null), btn = useRef(null), focusEl = useRef(null);
  const ws = u.words(q);
  const list = searchable && ws.length ? options.filter(o => u.hasWords(u.hayOf(o.label), ws) || o.id.includes(q.trim().toLowerCase())) : options;
  useEffect(() => {
    if (!open) return;
    const off = e => {
      if (wrap.current && !wrap.current.contains(e.target)) setOpen(false);
    };
    document.addEventListener("mousedown", off);
    if (focusEl.current) focusEl.current.focus();
    return () => document.removeEventListener("mousedown", off);
  }, [open]);
  useEffect(() => {
    setHi(0);
  }, [q]);
  const onKey = e => {
    if (e.key === "ArrowDown") {
      e.preventDefault();
      setHi(h => Math.min(list.length - 1, h + 1));
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setHi(h => Math.max(0, h - 1));
    } else if (e.key === "Enter" || e.key === " " && !searchable) {
      e.preventDefault();
      if (list[hi]) onToggle(list[hi].id);
    } else if (e.key === "Escape" || e.key === "Tab") {
      if (e.key === "Escape") {
        e.preventDefault();
        e.stopPropagation();
        if (btn.current) btn.current.focus();
      }
      setOpen(false);
    }
  };
  useEffect(() => {
    const el = open && wrap.current && wrap.current.querySelector(`#${id}-o-${hi}`);
    if (el) u.safe(() => el.scrollIntoView({
      block: "nearest"
    }));
  }, [hi, open]);
  const value = selected.length === 0 ? allLabel : selected.length === 1 ? u.label(options, selected[0]) : `${selected.length} selected`;
  const renderOpt = o => {
    const i = list.indexOf(o);
    return <TsMsOption key={o.id} id={`${id}-o-${i}`} label={o.label} mono={mono} selected={selected.includes(o.id)} highlighted={i === hi} count={counts[o.id]} onHover={() => setHi(i)} onPick={() => onToggle(o.id)} />;
  };
  const statusOpts = mono ? list.filter(o => o.status) : [];
  const nameOpts = mono ? list.filter(o => !o.status) : list;
  return <div className="sts-menu-wrap" ref={wrap}>
      <button ref={btn} type="button" className="sts-menu-btn" aria-haspopup="listbox" aria-expanded={open} aria-controls={`${id}-list`} data-set={selected.length ? "" : undefined} onClick={() => {
    setQ("");
    setHi(0);
    setOpen(!open);
  }} onKeyDown={e => {
    if (!open && (e.key === "ArrowDown" || e.key === "ArrowUp")) {
      e.preventDefault();
      setOpen(true);
    }
  }}>
        <span className="sts-menu-pre">{prefix}</span>
        <span className={selected.length === 1 && mono ? "sts-menu-val sts-mono" : "sts-menu-val"}>{value}</span>
        <TsIcon k="chev" />
      </button>
      {open && <div className="sts-menu" onKeyDown={onKey}>
          {searchable && <div className="sts-menu-search">
              <TsIcon k="search" size={14} />
              <input ref={focusEl} value={q} onChange={e => setQ(e.target.value)} placeholder={`Find a ${prefix.toLowerCase()}`} aria-label={`Find a ${prefix.toLowerCase()}`} aria-controls={`${id}-list`} aria-activedescendant={list.length ? `${id}-o-${hi}` : undefined} />
            </div>}
          <ul ref={searchable ? null : focusEl} id={`${id}-list`} role="listbox" aria-multiselectable="true" aria-label={prefix} tabIndex={searchable ? undefined : -1} aria-activedescendant={!searchable && list.length ? `${id}-o-${hi}` : undefined}>
            {mono && statusOpts.length > 0 && <li role="presentation" className="sts-menu-group">HTTP status</li>}
            {mono && statusOpts.map(renderOpt)}
            {mono && nameOpts.length > 0 && <li role="presentation" className="sts-menu-group">Error names</li>}
            {nameOpts.map(renderOpt)}
            {!list.length && <li role="presentation" className="sts-menu-none">No {prefix.toLowerCase()} matches “{q.trim()}”.</li>}
          </ul>
          {selected.length > 0 && <button type="button" className="sts-menu-clear" onClick={onClear}>Clear {prefix.toLowerCase()} filter</button>}
          {note && <div className="sts-menu-note">{note}</div>}
        </div>}
    </div>;
};

export const TsCatalogLinks = () => <>
    {TS.catalogs.map((c, i) => <span key={c.href}>
        {i > 0 && (i === TS.catalogs.length - 1 ? ", or " : ", ")}
        <a href={c.href}>{c.label}</a>
      </span>)}
  </>;

export const TsIntro = ({title = "Troubleshooting", titleId = "ts-hub-page-title", kicker = TS.kicker, children}) => <header className="sts sts-intro">
    <p className="sts-kicker">{kicker}</p>
    <h1 className="sts-page-title" id={titleId}>{title}</h1>
    {children && <p className="sts-lead">{children}</p>}
  </header>;

export const TsHubToolbar = () => {
  const u = tsUtil;
  const s = u.useStore();
  const [ready, setReady] = useState(false);
  const rows = s.rows || [];
  const topics = u.topicsFor(rows);
  const codes = u.codeIndex(rows);
  useEffect(() => {
    if (!s.rows || ready) return;
    const q = u.readQuery();
    const okList = (v, valid) => u.sp(v).map(x => x.toLowerCase()).filter(x => valid.includes(x));
    u.setStore({
      q: q.get("q") || "",
      topic: topics.some(t => t.id === q.get("topic")) ? q.get("topic") : "all",
      products: okList(q.get("product"), TS.products.map(p => p.id)),
      codes: okList(q.get("code"), codes.map(c => c.id))
    });
    setReady(true);
  }, [s.rows]);
  useEffect(() => {
    if (!ready) return;
    const q = u.readQuery();
    [["q", s.q.trim()], ["topic", s.topic === "all" ? "" : s.topic], ["product", s.products.join(",")], ["code", s.codes.join(",")]].forEach(([k, v]) => {
      if (v) q.set(k, v); else q.delete(k);
    });
    u.writeQuery(q);
  }, [s.q, s.topic, s.products, s.codes, ready]);
  const count = (key, list, field) => {
    const out = {};
    list.forEach(o => {
      out[o.id] = rows.filter(r => u.matches(r, s, key) && (field === "errors" ? u.hasCode(r, o.id) : r[field].includes(o.id))).length;
    });
    return out;
  };
  const prodCounts = count("products", TS.products, "prodSet");
  const codeCounts = count("codes", codes, "errors");
  const topicRows = rows.filter(r => u.matches(r, s, "topic"));
  const shown = rows.filter(r => u.matches(r, s)).length;
  const on = u.filtering(s);
  return <div className="sts sts-toolbar">
      <div className="sts-tools">
        <div className="sts-search">
          <TsIcon k="search" size={18} />
          <input type="search" value={s.q} placeholder="Paste an error code or describe the problem" aria-label="Search troubleshooting guides" autoComplete="off" onChange={e => u.setStore({
    q: e.target.value
  })} />
          {s.q && <button type="button" className="sts-search-x" aria-label="Clear search" onClick={() => u.setStore({
    q: ""
  })}><TsIcon k="close" size={14} /></button>}
        </div>
        <TsMenu id="sts-prod" prefix="Product" allLabel="All products" options={TS.products} selected={s.products} counts={prodCounts} onToggle={id => u.toggleIn("products", id)} onClear={() => u.setStore({
    products: []
  })} />
        <TsMenu id="sts-code" prefix="Error code" allLabel="Any code" options={codes} selected={s.codes} counts={codeCounts} searchable mono onToggle={id => u.toggleIn("codes", id)} onClear={() => u.setStore({
    codes: []
  })} note={<>Full catalogs: <TsCatalogLinks /> error messages.</>} />
      </div>

      <div className="sts-topics" role="group" aria-label="Filter by topic">
        {[{
    id: "all",
    label: "All",
    icon: "all"
  }, ...topics].map(t => {
    const n = t.id === "all" ? topicRows.length : topicRows.filter(r => r.topic === t.id).length;
    return <button key={t.id} type="button" className="sts-topic" aria-pressed={s.topic === t.id} data-zero={!n && t.id !== "all" ? "" : undefined} onClick={() => u.setStore({
      topic: t.id
    })}>
              <span className="sts-topic-l"><TsIcon k={t.icon} />{t.label}</span>
              {s.rows && <span className="sts-topic-n">{n}</span>}
            </button>;
  })}
      </div>

      <div className="sts-result" aria-live="polite">
        {s.rows && <span>{on ? <>Showing <b>{shown}</b> of {u.plural(rows.length, "guide")}</> : u.plural(rows.length, "guide")}</span>}
        {s.products.map(id => <button key={id} type="button" className="sts-chip" onClick={() => u.toggleIn("products", id)} aria-label={`Remove ${u.label(TS.products, id)} filter`}>
            {u.label(TS.products, id)}<TsIcon k="close" size={12} />
          </button>)}
        {s.codes.map(id => <button key={id} type="button" className="sts-chip" onClick={() => u.toggleIn("codes", id)} aria-label={`Remove ${id} filter`}>
            <span className="sts-mono">{u.label(codes, id)}</span><TsIcon k="close" size={12} />
          </button>)}
        {on && <button type="button" className="sts-clear" onClick={u.clearAll}><TsIcon k="reset" size={14} />Clear filters</button>}
      </div>
    </div>;
};

export const TsHubEmpty = () => {
  const u = tsUtil;
  const s = u.useStore();
  if (!s.rows || !s.rows.length || s.rows.some(r => u.matches(r, s))) return null;
  const q = s.q.trim();
  return <div className="sts sts-empty" role="status">
      <p className="sts-empty-t">{q ? <>No guide covers “{q}” yet.</> : "No guides match these filters."}</p>
      <p className="sts-empty-d">Check the spelling of the error code, or try fewer filters. If you're still stuck, send Technical Support the error code and the <code>request_id</code> from the response.</p>
      <p className="sts-empty-d sts-empty-cat">Look up the full error ID on the <TsCatalogLinks /> error messages pages.</p>
      <div className="sts-empty-a">
        <button type="button" className="sts-btn" onClick={u.clearAll}><TsIcon k="reset" size={14} />Clear filters</button>
        <a className="sts-btn sts-btn-yellow" href={TS.support.href}><TsIcon k="mail" size={16} />{TS.support.label}</a>
      </div>
    </div>;
};

export const HubShell = ({wrapClass, containerClass = "sdk-overview-container", tutHub, cookbookHub, disableReadTime, children}) => <div className={wrapClass} {...disableReadTime ? {
  "data-disable-read-time": "true"
} : {}} {...tutHub ? {
  "data-tut-hub": ""
} : {}} {...cookbookHub ? {
  "data-cookbook-hub": ""
} : {}}>
    <div className={containerClass}>{children}</div>
  </div>;

<HubShell wrapClass="hp-wrap cookbook-hp-wrap ts-hub-wrap" disableReadTime>
  <TsIntro title="Troubleshooting" titleId="ts-hub-page-title">
    Search or browse troubleshooting guides for solutions to common Suki authentication, streaming, session, SDK, and webhook issues.
  </TsIntro>

  <TsHubToolbar />

  <TsHubList>
    <TsHubRow href="/documentation/troubleshooting/invalid-partner-token-401" title="401 Unauthorized or invalid Partner Token" code="401 · invalid_sdp_token" products="authentication apis" product="authentication apis web-sdk mobile-sdk headless-web-sdk" error="401 invalid_sdp_token provider_not_registered invalidPartnerId" tags="auth" search="401 unauthorized invalid partner token jwt expired login authentication invalid_sdp_token" />

    <TsHubRow href="/documentation/troubleshooting/invalid-partner-details" title="InvalidPartnerDetails during sign-in or registration" code="InvalidPartnerDetails" products="authentication headless-web-sdk" product="authentication headless-web-sdk web-sdk" error="InvalidPartnerDetails UserNotFound invalidPartnerId SDKNotInitilized 401" tags="auth" search="InvalidPartnerDetails partner id partner token sign-in registration UserNotFound" />

    <TsHubRow href="/documentation/troubleshooting/suki-token-expired" title="Suki Token expired during a long session" code="401 · invalid_sdp_token" products="authentication apis" product="authentication apis form-filling web-sdk" error="401 invalid_sdp_token" tags="auth" search="suki token expired refresh login sdp_suki_token one hour invalid_sdp_token" />

    <TsHubRow href="/documentation/troubleshooting/session-already-exists" title="sessionAlreadyExists remote session conflict" code="sessionAlreadyExists · 409" products="ambient headless-web-sdk" product="ambient headless-web-sdk mobile-sdk" error="409 sessionAlreadyExists remoteSessionConflict sessionInProgress" tags="sessions" search="sessionAlreadyExists 409 blockingSessionId cancelRemote endRemote encounter remoteSessionConflict" />

    <TsHubRow href="/documentation/troubleshooting/microphone-permission-denied" title="Microphone permission denied or AudioRecorderFailure" code="AudioRecorderFailure" products="ambient headless-web-sdk" product="ambient headless-web-sdk web-sdk dictation mobile-sdk" error="AudioRecorderFailure StartSessionFailed needMicrophonePermissionRecording unableToStartRecording" tags="microphone" search="microphone permission denied AudioRecorderFailure getUserMedia deviceId needMicrophonePermissionRecording" />

    <TsHubRow href="/documentation/troubleshooting/websocket-disconnects-ambient" title="WebSocket disconnects during ambient streaming" code="StreamError · error_streaming_audio" products="ambient streaming" product="ambient streaming apis" error="error_streaming_audio client_disconnected 500 504 FailedPrecondition" tags="streaming" search="websocket disconnect ambient streaming StreamError connection drop error_streaming_audio" />

    <TsHubRow href="/documentation/troubleshooting/empty-notes-after-end-session" title="Empty or incomplete notes after ending an ambient session" code="ambient_session_not_found" products="ambient apis" product="ambient apis" error="404 session_wrong_state 412 skipped failed aborted" tags="sessions" search="empty notes incomplete content poll status after end session generation ambient_session_not_found" />

    <TsHubRow href="/documentation/troubleshooting/csp-blocks-sdk-iframe" title="CSP blocks the SDK iframe" code="CSP · SUKI_FF_002" products="form-filling dictation web-sdk" product="form-filling dictation web-sdk" error="CSP SUKI_FF_002" tags="csp" search="csp content security policy frame-src iframe sdk.suki.ai sdk.suki-stage.com handshake-timeout" />

    <TsHubRow href="/documentation/troubleshooting/form-filling-no-results" title="Form filling session returns no results" code="SUKI_FF_001" products="form-filling" product="form-filling web-sdk" error="SUKI_FF_001 SUKI_FF_002 SUKI_FF_003 SUKI_FF_004" tags="sessions" search="form filling no results empty fields session status template SUKI_FF_001" />

    <TsHubRow href="/documentation/troubleshooting/dictation-websocket-handshake" title="Dictation WebSocket handshake fails" code="400 · StreamError" products="dictation streaming" product="dictation streaming apis" error="400 401 404 invalid_request FailedPrecondition client_disconnected" tags="streaming" search="dictation websocket handshake transcription session open stream" />

    <TsHubRow href="/documentation/troubleshooting/webhook-deliveries-not-arriving" title="Webhook deliveries are not arriving" code="" products="webhooks" product="webhooks" error="403 permission_denied" tags="webhooks" search="webhook not receiving deliveries signature hmac endpoint" />

    <TsHubRow href="/documentation/troubleshooting/app-is-not-active-mobile" title="AppIsNotActive when starting Mobile SDK recording" code="appIsNotActive" products="mobile-sdk" product="mobile-sdk ambient" error="appIsNotActive AppIsNotActive" tags="microphone" search="AppIsNotActive appIsNotActive background recording iOS mobile foreground" />

    <TsHubRow href="/documentation/troubleshooting/mic-is-in-use-mobile" title="micIsInUse on Mobile SDK" code="micIsInUse" products="mobile-sdk" product="mobile-sdk" error="micIsInUse unableToStartRecording" tags="microphone" search="micIsInUse microphone in use another app mobile" />

    <TsHubRow href="/documentation/troubleshooting/wav-header-streamed-as-audio" title="WAV header streamed as audio data" code="" products="streaming ambient" product="ambient dictation streaming apis" error="invalid_request 400" tags="streaming" search="wav header pcm base64 audio quality recognition file stream" />

    <TsHubRow href="/documentation/troubleshooting/wrong-environment-endpoints" title="Wrong staging vs production endpoints" code="" products="authentication apis" product="authentication apis" error="401 404 invalid_sdp_token" tags="platform" search="staging production environment wrong endpoint stage suki.ai" />

    <TsHubRow href="/documentation/troubleshooting/provider-register-login-fails" title="Provider register or login fails" code="provider_not_registered" products="authentication" product="authentication apis" error="401 412 InvalidPartnerDetails provider_not_registered provider_user_inactive UserNotFound" tags="auth" search="register login provider fails partner token provider_id provider_not_registered" />

    <TsHubRow href="/documentation/troubleshooting/content-generation-slow" title="Content generation is taking too long" code="" products="ambient mobile-sdk" product="ambient mobile-sdk apis" error="504 unableFetchContent ServiceError" tags="sessions" search="content generation slow long delay note processing timeout" />

    <TsHubRow href="/documentation/troubleshooting/offline-upload-failures-mobile" title="Offline upload failures on Mobile SDK" code="audioUploadFailed" products="mobile-sdk" product="mobile-sdk" error="audioUploadFailed audioUploadAllRetryFailed processingUploadFailed" tags="offline" search="offline upload failures mobile network connectivity audioUploadFailed pendingOfflineUpload" />

    <TsHubRow href="/documentation/troubleshooting/network-offline-headless" title="NetworkOffline or OfflineSaveFailed on Headless Web SDK" code="NetworkOffline · OfflineSaveFailed" products="headless-web-sdk" product="headless-web-sdk ambient" error="NetworkOffline OfflineSaveFailed StartSessionFailed SubmitSessionFailed" tags="offline" search="NetworkOffline OfflineSaveFailed IndexedDB offline headless start submit browser storage" />

    <TsHubRow href="/documentation/troubleshooting/session-in-progress" title="session_in_progress on Partner API create" code="session_in_progress · 409" products="ambient apis" product="ambient apis" error="409 session_in_progress" tags="sessions" search="session_in_progress 409 concurrent ambient create emr_encounter_id blocking session" />

    <TsHubRow href="/documentation/troubleshooting/permission-denied-403" title="403 permission_denied, insufficient_scope, or sbac_denied" code="403 · permission_denied" products="authentication apis" product="authentication apis form-filling" error="403 permission_denied insufficient_scope sbac_denied" tags="auth" search="403 permission_denied insufficient_scope sbac_denied sdp.write organization access" />

    <TsHubRow href="/documentation/troubleshooting/content-rewrite-fails" title="Content rewrite returns 400, 403, or 500" code="invalid_rewrite_content_request · content_rewrite_not_enabled" products="dictation apis" product="dictation apis" error="400 401 403 500 invalid_rewrite_content_request content_rewrite_not_enabled failed_to_get_enable_content_rewrite_config failed_to_get_user_specialty provider_user_inactive" tags="sessions" search="content rewrite fails invalid_rewrite_content_request content_rewrite_not_enabled dictation rewrite CONCISE VERBOSE PATIENT_FRIENDLY request_id" />

    <TsHubRow href="/documentation/troubleshooting/form-filling-api-empty-results" title="Form filling API returns empty structured data" code="" products="form-filling apis" product="form-filling apis" error="failed aborted completed" tags="sessions" search="form filling api empty structured data poll status completed before retrieve" />

    <TsHubRow href="/documentation/troubleshooting/patient-summary-not-ready" title="Patient Summary empty or not ready" code="" products="apis patient-summary" product="apis patient-summary" error="403 permission_denied FAILED ABORTED" tags="sessions" search="patient summary empty not ready poll status COMPLETED ingestion FAILED" />
  </TsHubList>

  <TsHubEmpty />
</HubShell>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.