Xử lý lỗi
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ệ
Exception
└── VnstockError
├── InputError (cũng là ValueError)
├── AuthError
├── EntitlementError
├── NetworkError
│ └── DataSourceBlockedError
│ ├── RateLimitedError
│ ├── AccessDeniedError
│ ├── ChallengeRequiredError
│ └── CircuitOpenError
├── ProviderError
├── SchemaError
├── UnsupportedError
└── InternalErrorImport từ một chỗ:
from vnstock.core.exceptions import (
VnstockError, InputError, AuthError, EntitlementError, NetworkError,
ProviderError, SchemaError, UnsupportedError, InternalError,
DataSourceBlockedError, RateLimitedError, AccessDeniedError,
ChallengeRequiredError, CircuitOpenError,
)| Ngoại lệ | Khi nào | Nên làm gì |
|---|---|---|
VnstockError | Lớp gốc, mọi lỗi của thư viện đều thuộc lớp này | Bắt khi muốn chặn mọi lỗi của thư viện ở một chỗ |
InputError | Tham số sai: mã không có, ngày sai dạng, khung nến không hợp lệ, kỳ báo cáo sai | Sửa lời gọi. Thử lại không giúp gì |
AuthError | Khoá 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 |
EntitlementError | Hà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 khung | Xem Cấp tài khoản và giới hạn; với hết lượt, chờ rồi gọi lại |
NetworkError | Không kết nối được tới nguồn hoặc tới vnstocks.com | Kiểm tra mạng, thử lại sau |
DataSourceBlockedError | Nguồn từ chối yêu cầu, không phải mạng hỏng | Xem ba lớp con bên dưới |
RateLimitedError | Nguồn báo gọi quá nhanh (HTTP 429) | Chờ rồi gọi lại, giảm tần suất |
AccessDeniedError | Nguồn từ chối truy cập (HTTP 403), thường do hạn chế truy cập tự động | Tạm dừng gọi nguồn đó, thử lại sau hoặc dùng nguồn khác |
ChallengeRequiredError | Nguồn trả một trang kiểm tra chống truy cập tự động thay cho dữ liệu | Thư viện không vượt qua bước này. Dùng nguồn khác |
CircuitOpenError | Giữ để except của mã cũ vẫn chạy; thế hệ 5 hiện không ném lỗi này | Không cần xử lý riêng |
ProviderError | Nguồn trả lỗi, hoặc trả dữ liệu không đọc được | Thử lại sau; nếu lặp lại, nguồn có thể đã đổi cách trả dữ liệu |
SchemaError | Dữ liệu từ nguồn không khớp cấu trúc cột chuẩn của hàm | Báo lại kèm vnstock doctor; dùng nguồn khác trong lúc chờ |
UnsupportedError | Hà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ể |
InternalError | Lỗi bên trong thư viện | Bá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ếtexcept ValueErrorchovnstock_datavẫn bắt được lỗi mã không tồn tại.- Ở
vnstock_data,DataSourceBlockedErrorvà các lớp con nằm thẳng dướiVnstockError. Ở thế hệ 5 chúng nằm dướiNetworkError. Mọiexcepttừng chạy vẫn chạy;except NetworkErrornay 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ính | Kiểu | Ý nghĩa |
|---|---|---|
code | str | Mã lỗi ổn định, ví dụ VNSTOCK_TIER_ROUTE. Dùng để rẽ nhánh |
kind | str | Nhóm lỗi: input, auth, entitlement, network, provider, schema, unsupported, internal |
route | str hoặc None | Tuyến đang gọi, ví dụ market.equity.ohlcv |
provider | str hoặc None | Nguồn liên quan, ví dụ vci |
status | int hoặc None | Mã HTTP nguồn trả về, nếu có |
retryable | bool | True khi gọi lại sau có thể thành công |
action | str hoặc None | Việc nên làm tiếp, theo ngôn ngữ đang chọn |
message_vi, message_en | str | Thông báo tiếng Việt, tiếng Anh |
action_vi, action_en | str hoặc None | Việ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):
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ĩa | Cách xử lý |
|---|---|---|---|
VNSTOCK_TIER_ROUTE | EntitlementError | Hà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_SOURCE | EntitlementError | Nguồn source= không thuộc cấp của bạn | Bỏ source= hoặc chọn nguồn của cấp mình |
VNSTOCK_TIER_RULE_MISSING | EntitlementError | Chính sách chưa có quy tắc cho cấp của bạn | Cập nhật thư viện; xem tình trạng ở vnstocks.com |
VNSTOCK_AUTH_MINUTE_LIMIT | EntitlementError | Gọ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_LIMIT | EntitlementError | Đã 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_LIMIT | EntitlementError | Đã 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_LIMIT | EntitlementError | Tài khoản đã dùng hết số thiết bị được phép | Gỡ bớt thiết bị ở trang tài khoản |
Xác thực
| Mã | Ngoại lệ | Ý nghĩa | Cách xử lý |
|---|---|---|---|
VNSTOCK_AUTH_CREDENTIAL_INVALID | AuthError | Khoá API không hợp lệ hoặc đã bị thu hồi | Lấy khoá mới ở trang tài khoản, chạy vnstock register |
VNSTOCK_AUTH_CREDENTIAL_MISSING | AuthError | Khoá 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_INACTIVE | AuthError | Thiết bị chưa đăng ký hoặc đã bị gỡ khỏi tài khoản | Chạy lại vnstock register |
VNSTOCK_SOURCE_UNAUTHORIZED | AuthError | Nguồ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_UNKNOWN | InputError | Nguồn không có mã này. Tra mã trong Reference().equity.list() |
VNSTOCK_INPUT_SYMBOL, VNSTOCK_INPUT_SYMBOLS | InputError | Mã trống hoặc sai dạng; cần ít nhất một mã |
VNSTOCK_INPUT_START_DATE, VNSTOCK_INPUT_END_DATE | InputError | Ngày không theo dạng YYYY-MM-DD |
VNSTOCK_INPUT_DATE_RANGE | InputError | start sau end |
VNSTOCK_INPUT_INTERVAL | InputError | Khung nến không hợp lệ |
VNSTOCK_INPUT_PERIOD | InputError | period phải là year (Y) hoặc quarter (Q) |
VNSTOCK_INPUT_LIMIT | InputError | limit ngoài khoảng nguồn nhận |
VNSTOCK_INPUT_EXCHANGE, VNSTOCK_INPUT_GROUP | InputError | Sàn hoặc nhóm mã không hợp lệ, hoặc thiếu |
VNSTOCK_INPUT_LANGUAGE | InputError | Ngô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ĩa | Cách xử lý |
|---|---|---|---|
VNSTOCK_SOURCE_RATE_LIMITED | RateLimitedError | Nguồn đang giới hạn tần suất (HTTP 429). Thư viện dừng ngay, không thử lại | Chờ khoảng một phút, giảm tần suất, xin ít dòng hơn mỗi lần |
VNSTOCK_SOURCE_BLOCKED | AccessDeniedError | Nguồ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_CHALLENGE | ChallengeRequiredError | Nguồn trả trang kiểm tra chống truy cập tự động | Dùng nguồn khác |
VNSTOCK_SOURCE_UNAVAILABLE | NetworkError | Nguồ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_FOUND | ProviderError | Nguồ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_REJECTED | ProviderError | Nguồn trả mã HTTP khác và không có dữ liệu | Thử lại sau |
VNSTOCK_TRANSPORT_SEND | NetworkError | Không gửi được truy vấn tới nguồn | Kiểm tra mạng, proxy |
VNSTOCK_SOURCE_DISABLED | UnsupportedError | Nguồn đang được tạm tắt từ vnstocks.com, thông báo kèm lý do | Dùng nguồn khác. Không ghi đè được trên máy |
VNSTOCK_HOST_DISABLED | UnsupportedError | Một máy chủ của nguồn đang được tạm tắt từ vnstocks.com | Như trên |
VNSTOCK_POLICY_UNAVAILABLE | NetworkError | Khô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ạy | Kiể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ĩa | Cách xử lý |
|---|---|---|---|
VNSTOCK_FEATURE_REMOVED | UnsupportedError | Hà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_UNAVAILABLE | UnsupportedError | Nguồ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_MIGRATED | UnsupportedError | Bản đang cài chưa hỗ trợ hàm này | Cập nhật thư viện |
VNSTOCK_RELEASE_EXPIRED | UnsupportedError | Bản đang cài đã hết hạn dùng | Cập nhật bằng lệnh trong e.action |
VNSTOCK_RELEASE_DISABLED | UnsupportedError | Bản đang cài đã bị tắt từ vnstocks.com, thông báo kèm lý do | Cậ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):
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ó:
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:
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}")
raiseMuốn rẽ nhánh theo một mã cụ thể thay vì theo lớp:
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:
raiseThư 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:
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áo | Khi nào |
|---|---|
UserWarning | Kế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 |
FutureWarning | Bả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 |
DeprecationWarning | Tê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:
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
vnstock doctor
vnstock versionHai lệnh này không in khoá API hay định danh thiết bị đầy đủ.