Vnstock Logo

Xử lý lỗi

Mở rộng

Mục lục

Hàm của vnstock thế hệ 5 hoặc trả bảng dữ liệu, hoặc ném một ngoại lệ có kiểu. Thư viện không in lỗi ra màn hình rồi trả None. Mỗi ngoại lệ mang một mã ổn định ở e.code để mã của bạn rẽ nhánh, và một gợi ý việc nên làm ở e.action.

Cây ngoại lệ

Text
Exception
└── VnstockError
    ├── InputError              (cũng là ValueError)
    ├── AuthError
    ├── EntitlementError
    ├── NetworkError
    │   └── DataSourceBlockedError
    │       ├── RateLimitedError
    │       ├── AccessDeniedError
    │       ├── ChallengeRequiredError
    │       └── CircuitOpenError
    ├── ProviderError
    ├── SchemaError
    ├── UnsupportedError
    └── InternalError

Import từ một chỗ:

Python
from vnstock.core.exceptions import (
    VnstockError, InputError, AuthError, EntitlementError, NetworkError,
    ProviderError, SchemaError, UnsupportedError, InternalError,
    DataSourceBlockedError, RateLimitedError, AccessDeniedError,
    ChallengeRequiredError, CircuitOpenError,
)
Ngoại lệKhi nàoNên làm gì
VnstockErrorLớp gốc, mọi lỗi của thư viện đều thuộc lớp nàyBắt khi muốn chặn mọi lỗi của thư viện ở một chỗ
InputErrorTham số sai: mã không có, ngày sai dạng, khung nến không hợp lệ, kỳ báo cáo saiSửa lời gọi. Thử lại không giúp gì
AuthErrorKhoá API thiếu, sai, bị thu hồi; thiết bị chưa đăng ký hoặc đã bị gỡChạy vnstock register hoặc kiểm tra thiết bị ở trang tài khoản
EntitlementErrorHàm hay nguồn chưa mở cho cấp của bạn, hoặc đã dùng hết lượt gọi trong một khungXem Cấp tài khoản và giới hạn; với hết lượt, chờ rồi gọi lại
NetworkErrorKhông kết nối được tới nguồn hoặc tới vnstocks.comKiểm tra mạng, thử lại sau
DataSourceBlockedErrorNguồn từ chối yêu cầu, không phải mạng hỏngXem ba lớp con bên dưới
RateLimitedErrorNguồn báo gọi quá nhanh (HTTP 429)Chờ rồi gọi lại, giảm tần suất
AccessDeniedErrorNguồn từ chối truy cập (HTTP 403), thường do hạn chế truy cập tự độngTạm dừng gọi nguồn đó, thử lại sau hoặc dùng nguồn khác
ChallengeRequiredErrorNguồn trả một trang kiểm tra chống truy cập tự động thay cho dữ liệuThư viện không vượt qua bước này. Dùng nguồn khác
CircuitOpenErrorGiữ để except của mã cũ vẫn chạy; thế hệ 5 hiện không ném lỗi nàyKhông cần xử lý riêng
ProviderErrorNguồn trả lỗi, hoặc trả dữ liệu không đọc đượcThử lại sau; nếu lặp lại, nguồn có thể đã đổi cách trả dữ liệu
SchemaErrorDữ liệu từ nguồn không khớp cấu trúc cột chuẩn của hàmBáo lại kèm vnstock doctor; dùng nguồn khác trong lúc chờ
UnsupportedErrorHàm, giá trị hay nguồn không được phục vụ; hàm đã ngừng; bản đang cài đã hết hạn hoặc bị tắtĐọc e.code và e.action để biết lý do cụ thể
InternalErrorLỗi bên trong thư việnBáo lại kèm vnstock doctor và vnstock version

Hai điểm về tương thích với mã cũ:

  • InputError đồng thời là ValueError. Mã viết except ValueError cho vnstock_data vẫn bắt được lỗi mã không tồn tại.
  • Ở vnstock_data, DataSourceBlockedError và các lớp con nằm thẳng dưới VnstockError. Ở thế hệ 5 chúng nằm dưới NetworkError. Mọi except từng chạy vẫn chạy; except NetworkError nay bắt thêm được các lỗi nguồn từ chối.

Thuộc tính của mỗi lỗi

Mọi ngoại lệ kế thừa VnstockError mang các thuộc tính sau:

Thuộc tínhKiểuÝ nghĩa
codestrMã lỗi ổn định, ví dụ VNSTOCK_TIER_ROUTE. Dùng để rẽ nhánh
kindstrNhóm lỗi: input, auth, entitlement, network, provider, schema, unsupported, internal
routestr hoặc NoneTuyến đang gọi, ví dụ market.equity.ohlcv
providerstr hoặc NoneNguồn liên quan, ví dụ vci
statusint hoặc NoneMã HTTP nguồn trả về, nếu có
retryableboolTrue khi gọi lại sau có thể thành công
actionstr hoặc NoneViệc nên làm tiếp, theo ngôn ngữ đang chọn
message_vi, message_enstrThông báo tiếng Việt, tiếng Anh
action_vi, action_enstr hoặc NoneViệc nên làm, tiếng Việt, tiếng Anh

str(e) và e.action theo ngôn ngữ hiển thị đang chọn: mặc định cả hai, tiếng Việt trước. Đổi bằng vnstock settings language vi|en hoặc biến môi trường VNSTOCK_LANG. Cần một ngôn ngữ cố định trong log thì đọc thẳng e.message_vi hoặc e.message_en.

Ví dụ thật, gọi chỉ số tài chính ở cấp Khách (chạy ngày 10/10/2026):

Python
from vnstock import Fundamental
from vnstock.core.exceptions import EntitlementError

try:
    Fundamental().equity("FPT").ratio()
except EntitlementError as e:
    print(e.code)        # VNSTOCK_TIER_ROUTE
    print(e.kind)        # entitlement
    print(e.route)       # fundamental.equity.ratio
    print(e.retryable)   # False
    print(e.message_vi)  # Chức năng 'fundamental.equity.ratio' không thuộc quyền của cấp Khách.
    print(e.action_vi)
    # Đăng nhập bằng khoá API cấp Cộng đồng (lấy tại https://vnstocks.com/account#api-key),
    # hoặc xem các cấp tài trợ tại https://vnstocks.com/insiders-program.

Mã lỗi thường gặp

Cấp quyền và hạn mức

MãNgoại lệÝ nghĩaCách xử lý
VNSTOCK_TIER_ROUTEEntitlementErrorHàm không thuộc cấp của bạnĐăng nhập, hoặc xem các cấp tài trợ. Không gửi truy vấn nào đi
VNSTOCK_TIER_SOURCEEntitlementErrorNguồn source= không thuộc cấp của bạnBỏ source= hoặc chọn nguồn của cấp mình
VNSTOCK_TIER_RULE_MISSINGEntitlementErrorChính sách chưa có quy tắc cho cấp của bạnCập nhật thư viện; xem tình trạng ở vnstocks.com
VNSTOCK_AUTH_MINUTE_LIMITEntitlementErrorGọi quá nhanh so với nhịp của cấp (retryable=True)Chờ vài giây rồi gọi lại
VNSTOCK_AUTH_HOUR_LIMITEntitlementErrorĐã dùng hết hạn mức chung của giờ này (retryable=True)Chờ tới đầu giờ kế tiếp. Xem vnstock usage
VNSTOCK_AUTH_DAY_LIMIT, VNSTOCK_AUTH_MONTH_LIMITEntitlementErrorĐã dùng hết hạn mức chung của hôm nay hoặc tháng này. Hạn mức dùng chung cho mọi thư viện và thiết bịChờ tới 00:00 hôm sau hoặc ngày 1 tháng sau (giờ Việt Nam); đăng nhập nếu đang ở cấp Khách. Xem vnstock usage
VNSTOCK_AUTH_DEVICE_LIMITEntitlementErrorTài khoản đã dùng hết số thiết bị được phépGỡ bớt thiết bị ở trang tài khoản

Xác thực

MãNgoại lệÝ nghĩaCách xử lý
VNSTOCK_AUTH_CREDENTIAL_INVALIDAuthErrorKhoá API không hợp lệ hoặc đã bị thu hồiLấy khoá mới ở trang tài khoản, chạy vnstock register
VNSTOCK_AUTH_CREDENTIAL_MISSINGAuthErrorKhoá API trống, ví dụ biến VNSTOCK_API_KEY có nhưng rỗngĐặt lại khoá
VNSTOCK_AUTH_DEVICE_NOT_REGISTERED, VNSTOCK_AUTH_DEVICE_INACTIVEAuthErrorThiết bị chưa đăng ký hoặc đã bị gỡ khỏi tài khoảnChạy lại vnstock register
VNSTOCK_SOURCE_UNAUTHORIZEDAuthErrorNguồn từ chối vì chưa xác thực (HTTP 401)Kiểm tra phiên đăng nhập còn hiệu lực rồi thử lại

Tham số

MãNgoại lệÝ nghĩa
VNSTOCK_INPUT_SYMBOL_UNKNOWNInputErrorNguồn không có mã này. Tra mã trong Reference().equity.list()
VNSTOCK_INPUT_SYMBOL, VNSTOCK_INPUT_SYMBOLSInputErrorMã trống hoặc sai dạng; cần ít nhất một mã
VNSTOCK_INPUT_START_DATE, VNSTOCK_INPUT_END_DATEInputErrorNgày không theo dạng YYYY-MM-DD
VNSTOCK_INPUT_DATE_RANGEInputErrorstart sau end
VNSTOCK_INPUT_INTERVALInputErrorKhung nến không hợp lệ
VNSTOCK_INPUT_PERIODInputErrorperiod phải là year (Y) hoặc quarter (Q)
VNSTOCK_INPUT_LIMITInputErrorlimit ngoài khoảng nguồn nhận
VNSTOCK_INPUT_EXCHANGE, VNSTOCK_INPUT_GROUPInputErrorSàn hoặc nhóm mã không hợp lệ, hoặc thiếu
VNSTOCK_INPUT_LANGUAGEInputErrorNgôn ngữ phải là vi, en hoặc both

Một số giới hạn tham số là của riêng từng nguồn, nên mã lỗi mang tên nguồn, ví dụ VNSTOCK_VCI_TRADES_PAGE_LIMIT (nguồn vci nhận limit khớp lệnh từ 1 tới 1.000) hay VNSTOCK_VCI_INTERVAL_UNAVAILABLE (khung nến nguồn đó không có). Thông báo kèm theo nêu giá trị hợp lệ. Mã dạng VNSTOCK_<NGUỒN>_..._SHAPE hay ..._RESPONSE_JSON nghĩa là nguồn trả dữ liệu không đúng dạng mong đợi; xử lý như ProviderError.

Nguồn và mạng

MãNgoại lệÝ nghĩaCách xử lý
VNSTOCK_SOURCE_RATE_LIMITEDRateLimitedErrorNguồn đang giới hạn tần suất (HTTP 429). Thư viện dừng ngay, không thử lạiChờ khoảng một phút, giảm tần suất, xin ít dòng hơn mỗi lần
VNSTOCK_SOURCE_BLOCKEDAccessDeniedErrorNguồn từ chối (HTTP 403)Tạm dừng gọi nguồn đó; lặp lại thì dùng nguồn khác. Trên Google Colab, nguồn hay chặn cả dải địa chỉ đám mây: chạy trên máy của bạn
VNSTOCK_SOURCE_CHALLENGEChallengeRequiredErrorNguồn trả trang kiểm tra chống truy cập tự độngDùng nguồn khác
VNSTOCK_SOURCE_UNAVAILABLENetworkErrorNguồn tạm thời không phục vụ, hoặc không trả dữ liệu dùng được sau vài lần thửThử lại sau vài phút
VNSTOCK_SOURCE_NOT_FOUNDProviderErrorNguồn không có dữ liệu cho yêu cầu này (HTTP 404)Kiểm tra mã, khoảng thời gian, khung nến
VNSTOCK_SOURCE_REJECTEDProviderErrorNguồn trả mã HTTP khác và không có dữ liệuThử lại sau
VNSTOCK_TRANSPORT_SENDNetworkErrorKhông gửi được truy vấn tới nguồnKiểm tra mạng, proxy
VNSTOCK_SOURCE_DISABLEDUnsupportedErrorNguồn đang được tạm tắt từ vnstocks.com, thông báo kèm lý doDùng nguồn khác. Không ghi đè được trên máy
VNSTOCK_HOST_DISABLEDUnsupportedErrorMột máy chủ của nguồn đang được tạm tắt từ vnstocks.comNhư trên
VNSTOCK_POLICY_UNAVAILABLENetworkErrorKhông tải được chính sách hiện hành từ vnstocks.com; không có chính sách thì không lời gọi dữ liệu nào chạyKiểm tra kết nối tới vnstocks.com rồi thử lại

Hàm, nguồn và phiên bản

MãNgoại lệÝ nghĩaCách xử lý
VNSTOCK_FEATURE_REMOVEDUnsupportedErrorHàm hoặc nguồn đã ngừng, ví dụ Retail().gold(), Reference().company(s).news(), source="btmc"Thông báo nêu bản đã ngừng và nguồn thay thế nếu có. Xem các trang chuyển đổi
VNSTOCK_CAPABILITY_UNAVAILABLEUnsupportedErrorNguồn source= không phục vụ hàm này, hoặc là nguồn của bản cũ (msn, tcbs…)Thông báo liệt kê các nguồn dùng được
VNSTOCK_ROUTE_UNAVAILABLE, VNSTOCK_ROUTE_NOT_MIGRATEDUnsupportedErrorBản đang cài chưa hỗ trợ hàm nàyCập nhật thư viện
VNSTOCK_RELEASE_EXPIREDUnsupportedErrorBản đang cài đã hết hạn dùngCập nhật bằng lệnh trong e.action
VNSTOCK_RELEASE_DISABLEDUnsupportedErrorBản đang cài đã bị tắt từ vnstocks.com, thông báo kèm lý doCập nhật

Thông báo thật khi gọi hàm đã ngừng và khi truyền mã không có (chạy ngày 10/10/2026):

Python
from vnstock import Market, Retail
from vnstock.core.exceptions import InputError, UnsupportedError

try:
    Retail().gold()
except UnsupportedError as e:
    print(e.code)        # VNSTOCK_FEATURE_REMOVED
    print(e.message_vi)  # `Retail().gold()` đã ngừng hỗ trợ từ vnstock 5.0.0a3 và không còn trả dữ liệu.

try:
    Market().equity("ZZZQ").ohlcv(start="2026-10-01", end="2026-10-09")
except InputError as e:
    print(e.code)        # VNSTOCK_INPUT_SYMBOL_UNKNOWN
    print(e.provider)    # vci
    print(e.message_vi)  # Nguồn 'vci' không có mã 'ZZZQ'.
    print(e.action_vi)   # Kiểm tra lại mã, ví dụ tra trong Reference().equity.list().

Truyền nguồn mà hàm không có:

Text
Nguồn 'msn' không phục vụ market.equity.ohlcv. Nguồn dùng được: 'vci', 'asean', 'mas', 'kbs', 'vnd'.

Lỗi cấp quyền được kiểm trước nguồn: ở cấp Khách, source="mas" báo VNSTOCK_TIER_SOURCE dù nguồn đó có phục vụ hàm.


Bắt lỗi theo thứ tự hẹp tới rộng

Python dừng ở except đầu tiên khớp, nên đặt lớp con trước lớp cha:

Python
import time

from vnstock import Market
from vnstock.core.exceptions import (
    AuthError, EntitlementError, InputError, NetworkError,
    ProviderError, RateLimitedError, UnsupportedError, VnstockError,
)


def daily_bars(symbol, start, end):
    try:
        return Market().equity(symbol).ohlcv(start=start, end=end)
    except InputError:               # sửa lời gọi, đừng thử lại
        raise
    except (AuthError, EntitlementError) as e:
        if e.retryable:              # hết lượt theo phút hoặc giờ
            time.sleep(60)
            return Market().equity(symbol).ohlcv(start=start, end=end)
        raise                        # cấp hoặc khoá: thử lại không giúp gì
    except RateLimitedError:
        time.sleep(60)               # nguồn báo gọi quá nhanh
        return Market().equity(symbol).ohlcv(start=start, end=end)
    except (NetworkError, ProviderError) as e:
        print(f"[{e.code}] {e.message_vi}")
        return None
    except UnsupportedError as e:    # hàm đã ngừng, bản hết hạn, nguồn bị tắt
        print(e.action or e.message_vi)
        raise
    except VnstockError as e:        # mọi lỗi còn lại của thư viện
        print(f"[{e.code}] {e}")
        raise

Muốn rẽ nhánh theo một mã cụ thể thay vì theo lớp:

Python
try:
    df = Market().equity("FPT").ohlcv(start="2026-10-01", end="2026-10-09", source="mas")
except VnstockError as e:
    if e.code == "VNSTOCK_TIER_SOURCE":
        df = Market().equity("FPT").ohlcv(start="2026-10-01", end="2026-10-09")
    else:
        raise

Thư viện không tự chuyển nguồn

Mỗi lời gọi dùng đúng một nguồn: nguồn bạn chọn qua source=, nguồn đặt bằng set_route(), hoặc nguồn mặc định. Nguồn đó lỗi thì bạn nhận ngoại lệ, không nhận dữ liệu của nguồn khác.

Với lỗi xác thực và cấp quyền (AuthError, EntitlementError), thư viện dừng trước khi gửi bất kỳ truy vấn nào tới nguồn, và cũng không thử nguồn khác: đổi nguồn không thay đổi quyền của bạn. Lỗi tham số (InputError) cũng vậy.

Khi nguồn từ chối (RateLimitedError, AccessDeniedError, ChallengeRequiredError), thư viện dừng ngay, không thử lại trong cùng lời gọi, vì thử lại lúc nguồn đang chặn chỉ kéo dài thời gian bị chặn. Thư viện chỉ tự thử lại vài lần, có giãn cách, khi nguồn báo quá tải tạm thời hoặc kết nối đứt giữa chừng; hết số lần thử thì báo NetworkError mã VNSTOCK_SOURCE_UNAVAILABLE.

Muốn dự phòng sang nguồn thứ hai, tự viết vòng thử và chỉ bắt lỗi mạng hoặc lỗi nguồn. Ví dụ đầy đủ ở Nguồn dữ liệu.


Bộ ngắt mạch

vnstock_data giữ một bộ ngắt mạch theo máy chủ: sau nhiều lần bị từ chối, thư viện ngừng gọi máy chủ đó một thời gian. Thế hệ 5 không làm vậy. Mỗi lời gọi tự phân loại lỗi và dừng ngay, không nhớ trạng thái giữa các lời gọi.

Hai hàm và lớp lỗi cũ vẫn còn để mã cũ chạy:

Python
from vnstock import circuit_status, reset_circuit

circuit_status()   # {}  luôn rỗng: không có máy chủ nào đang tạm ngừng
reset_circuit()    # 0   không có gì để xoá

CircuitOpenError vẫn import được nhưng thư viện hiện không ném lỗi này. except CircuitOpenError trong mã cũ không gây lỗi, chỉ không bao giờ chạy tới.


Cảnh báo, không phải lỗi

Một số tình huống chỉ phát cảnh báo và vẫn trả dữ liệu:

Cảnh báoKhi nào
UserWarningKết quả bị cắt theo cấp (một lần cho mỗi loại cắt trong một phiên chạy). Con số nằm trong df.attrs, xem Cấp tài khoản và giới hạn
FutureWarningBản đang cài còn dưới 30 ngày dùng; hoặc bạn gọi tên cũ có ngày ngừng
DeprecationWarningTên cũ còn chạy, có tên mới thay

Muốn chương trình dừng khi kết quả bị cắt, đừng dựa vào cảnh báo: cảnh báo chỉ phát một lần mỗi phiên. Kiểm df.attrs sau mỗi lời gọi:

Python
if any(k.startswith("tier_cap_") for k in df.attrs):
    raise RuntimeError(f"Kết quả bị cắt theo cấp: {dict(df.attrs)}")

Cảnh báo về hạn dùng không bao giờ làm lời gọi thất bại, kể cả khi bạn biến mọi cảnh báo thành lỗi.


Khi cần báo lỗi

Gửi kèm ba thứ: e.code, toàn bộ str(e), và kết quả của

Shell
vnstock doctor
vnstock version

Hai lệnh này không in khoá API hay định danh thiết bị đầy đủ.