# FAQ and troubleshooting

Common questions and the quick fixes. If something here doesn't cover
your case, the relevant reference page usually does.

## Setup and keys

**"Error: No API key set."**
zfin needs at least `TIINGO_API_KEY` to fetch price history. Set it in
your environment or `.env`. See [Getting started](../getting-started.md)
and [environment variables](../reference/config/environment.md#api-keys).

**Total-return columns are blank or match price-only.**
Total return needs dividend data from Polygon -- set `POLYGON_API_KEY`.
Without it you get price-only returns. See
[Returns and performance](returns-and-performance.md#price-only-vs-total-return).

**ETF profiles or `enrich` don't work.**
SEC EDGAR requires a contact email. Set `ZFIN_USER_EMAIL` to your
address (it's not a key). See
[`zfin enrich`](../reference/cli/enrich.md).

## Missing or odd data

**A holding shows up as "Unclassified."**
It has no [`metadata.srf`](../reference/config/metadata-srf.md) entry,
or the entry's `symbol::` doesn't match the lot's `symbol::`/`ticker::`.
Add a classification line; see
[Classify your holdings](../guides/classify-holdings.md).

**An account shows as "Unknown" in the tax-type breakdown.**
It's missing from [`accounts.srf`](../reference/config/accounts-srf.md),
or the `account::` name doesn't match the lot's `account::` exactly
(names must match character-for-character). See
[Map your accounts](../guides/set-up-accounts.md).

**A stock or ETF shows "no earnings data."**
ETFs, mutual funds, CUSIPs, and some dual-class shares (e.g. BRK.B)
return no earnings on FMP's free tier. This is an expected limitation,
not a bug. See [Why multiple data providers](data-providers.md).

**A mutual fund price looks like yesterday's.**
Mutual-fund NAVs publish after market close (after midnight ET for some
funds), so intraday you'll see the prior NAV until the new one posts.

**`quote` says the symbol is unavailable, but `perf` works.**
You're probably in offline mode (`--refresh-data=never`). Quotes are
never cached, so offline there's nothing to serve; candle-based
commands still work from cache. See
[Caching and data freshness](caching.md#quotes-are-never-cached).

**A row is shown in warning (yellow) color.**
That's a manual-priced lot -- its price came from the lot's `price::`
field, not a live feed, so it may be stale. Update `price::` /
`price_date::`, or run [`zfin audit`](../reference/cli/audit.md) to find
stale ones.

## Behavior

**A run printed "(using cached data)."**
zfin served fresh-enough cached data instead of hitting the network --
normal and fast. Force a refetch with `--refresh-data=force`. See
[Offline use and refreshing data](../guides/offline-and-refresh.md).

**A refresh seems slow / pauses.**
The rate limiter is spacing requests to stay under a provider's
free-tier limit (e.g. Polygon 5/min). It blocks rather than failing.
See [rate limiting](caching.md#rate-limiting).

**zfin can't find my portfolio.**
It looks in `ZFIN_HOME` if set, otherwise the current directory. Set
`ZFIN_HOME` to your data directory, or `cd` into it. `accounts.srf` and
`metadata.srf` load from the same directory as the resolved
`portfolio.srf`. See
[core concepts](concepts.md#zfin_home-where-your-data-lives).

**CLI and TUI show different totals.**
They shouldn't -- both union-merge every `portfolio*.srf` in
`ZFIN_HOME`. If they differ, check whether you passed a narrowing `-p`
pattern to one but not the other, or whether one is using a stale
cache vs. live prices.

**`contributions` reports "No changes detected."**
It diffs git revisions of your portfolio. With a clean tree it compares
`HEAD~1..HEAD`; if your last commit didn't change holdings, there's
nothing to show. Use `--since` to widen the window. See
[Track contributions](../guides/track-contributions.md).

## Data hygiene

**Lots of "overdue for update" accounts in `audit`.**
The default cadence is weekly and nags until satisfied. Set
`update_cadence::monthly|quarterly|none` per account in
[`accounts.srf`](../reference/config/accounts-srf.md#update_cadence-and-the-audit-nag).

**A transfer between my accounts inflated my contributions.**
Declare it in
[`transaction_log.srf`](../reference/config/transaction-log-srf.md) so
it isn't counted as new money. See
[Track contributions](../guides/track-contributions.md#dont-double-count-transfers).

## See also

- [Core concepts](concepts.md) -- the mental model.
- [Documentation home](../README.md) -- everything else.
