Data Source Troubleshooting

When a TableCrafter table shows an error banner, a "Retry" button, or no rows, the cause is almost always in the data source layer. This page maps every real error TableCrafter raises to its root cause and fix, covering unreachable or blocked URLs, CORS, authentication failures, and empty or malformed data.

SSRF / Blocked URLs CORS Auth Failures Empty & Malformed Data Health Monitoring

How TableCrafter loads a source

Every table is rendered by the [tablecrafter] shortcode. The source attribute is the data URL, and the fetch pipeline runs in this order: local file resolution, then a security (SSRF) check, then the protocol-specific fetcher (Airtable, CSV/Google Sheets, or remote JSON). Understanding this order tells you where a failure happened.

// Minimal example - a remote JSON source
[tablecrafter source="https://api.example.com/products.json" root="data" search="true"]

There are two distinct render paths, and the error you see depends on which one ran:

ℹ️

Logged-in administrators see a detailed TableCrafter Setup Guide panel (.tc-admin-error-helper) with the raw error message. Visitors see only a generic .tc-error-state notice: "Unable to load data. Please check back later." Always reproduce issues while logged in as an admin so you can read the real error.

Reading the error message

TableCrafter returns a WP_Error with a specific code and message for each failure class. Match the message you see (in the admin helper, or in the proxy response prefixed with TableCrafter Proxy Error:) to the table below.

Error messageError codeMeaning
The provided URL is blocked for safety (Local/Private IP).security_errorSSRF guard blocked a localhost/private-range/invalid URL.
CURL Error: <detail>http_errorSource unreachable, DNS failure, TLS handshake failure, or timeout.
Source returned HTTP <code>http_errorServer replied with a non-200 status (404, 403, 500, etc.).
The source did not return a valid JSON structure.json_errorBody was not parseable JSON (often an HTML error page).
Path Error: Key '<x>' not found in data structure.path_errorThe root attribute points at a key that does not exist.
Empty Source: The data received is empty.Fetch succeeded but produced zero rows.

Unreachable or blocked sources

An http_error means TableCrafter reached the network layer but could not get a usable response. Work through these causes:

  1. Source returned HTTP 404 / 403 / 500 — open the exact source URL in a browser or with curl. If it 404s or requires a login, fix the URL or make the endpoint public. TableCrafter requires a 200 response.
  2. CURL Error / connection timeout — the host is unreachable from your server. Remote JSON has a 10-second connect and 30-second total timeout. Confirm outbound HTTP is allowed (some managed hosts block it) and that the host resolves via DNS.
  3. TLS / certificate errors — TableCrafter enforces SSL verification (CURLOPT_SSL_VERIFYPEER and sslverify are on) using WordPress's bundled CA bundle. A self-signed or expired certificate on the source will fail. Fix the certificate on the source rather than disabling verification.
💡

The client-side loader (TC_HTTP_Request) automatically retries transient failures up to 3 times with exponential backoff. It does not retry 4xx client errors (except 429), security blocks, or JSON parse errors — those are treated as permanent, so fix the source rather than reloading repeatedly.

"Blocked for safety" (SSRF protection)

The security_error comes from TC_Security::is_safe_url(), which runs WordPress core's wp_http_validate_url(). It rejects localhost, 127.0.0.1, [::1], private IP ranges (e.g. 10.x, 192.168.x), and malformed URLs. This is an intentional anti-SSRF measure, not a bug.

CORS errors (client-side only)

CORS only affects the direct browser fetch path. If the console shows a CORS or "blocked by CORS policy" error and the table falls back to renderError, the source server is not sending Access-Control-Allow-Origin for your domain.

The correct fix is to route the request through TableCrafter's server-side proxy, which fetches from PHP and is never subject to CORS. The proxy is the AJAX action tc_proxy_fetch; it requires the edit_posts capability and a valid tc_proxy_nonce. Because the server-rendered first paint already uses TC_Data_Fetcher server-side, simply ensuring the table renders on initial page load (rather than relying on a pure client fetch) sidesteps CORS for visitors.

⚠️

You cannot fix a CORS rejection from inside TableCrafter alone — the source server controls CORS headers. The plugin's mitigation is to fetch server-side; if direct client fetch is unavoidable, the upstream host must add the header.

Authentication failures

Auth failures appear most often with Airtable sources, which use the airtable:// protocol and a Personal Access Token (PAT). The token can be passed inline as ?token= or saved once in WordPress Admin → TableCrafter settings (stored encrypted via TC_Security::encrypt_token()).

// Airtable source: base id, table name, and a PAT
[tablecrafter source="airtable://appXXXXXXXX/Tasks?token=patXXXXXXXX&view=Grid"]
HTTP codeError codeCause & fix
airtable_no_tokenNo PAT supplied inline or saved. Add ?token= or save it in settings.
401airtable_auth_errorInvalid or revoked PAT. Regenerate the token in Airtable.
403airtable_permission_errorToken lacks access to that base/table. Grant the base scope to the PAT.
404airtable_not_foundWrong Base ID or Table Name. Verify both (Base IDs start with app).
429airtable_rate_limitRate limit hit. Airtable results are cached for 5 minutes; wait and retry.
500/502/503airtable_server_errorAirtable outage. Retry later.

For protected JSON APIs (not Airtable), TableCrafter's remote JSON fetcher does not send custom auth headers, so an endpoint requiring an API key in a header will return http_error with HTTP 401/403. Either make the endpoint public, embed the key in the query string if the API supports it, or front it with a public, read-only proxy.

Empty or malformed data

Here the fetch succeeded (HTTP 200) but the table is blank or wrong. Diagnose by symptom:

SymptomLikely causeFix
"Empty Source: The data received is empty."Source returned [], {}, or all rows were filtered out.Confirm the source has rows; check include/exclude didn't remove every column.
"did not return a valid JSON structure"Body is HTML (a login wall or error page) or truncated JSON.Open the URL raw — if you see HTML, the endpoint isn't a JSON feed.
"Path Error: Key '…' not found"root points at a missing key.Inspect the JSON shape and set root to the real path (dot notation).
Table renders but columns are blankRows are not a flat list of objects.Use root to drill into the array of row objects.

TableCrafter expects the data to be (or resolve to, via root) an array of objects — one object per row, with each key becoming a column. The root attribute uses dot notation to reach a nested array:

// Source returns { "data": { "items": [ {…}, {…} ] } }
[tablecrafter source="https://api.example.com/feed.json" root="data.items"]
💡

CSV and Google Sheets: rows whose column count does not match the header row are silently skipped during parsing. If a Sheet shows fewer rows than expected, check for ragged rows, stray commas, or unescaped quotes. A leading byte-order mark (BOM) is stripped automatically from the first header. Google Sheets must be link-shareable (the plugin requests the public CSV export); a private Sheet returns an HTML login page and fails as json_error/empty.

Clearing stale cache after a fix

TableCrafter caches both the fetched data and the rendered HTML (transients prefixed tc_cache_ and tc_html_; Airtable for 5 minutes, others for 1 hour). After you fix a source you may still see the old error or old rows until the cache expires. Force a refresh with WP-CLI:

# Remove all TableCrafter data, HTML, and export transients
wp tablecrafter clear-cache

# Re-fetch every tracked source immediately
wp tablecrafter warm-cache

Proactive health monitoring

For sources that fail intermittently, TableCrafter ships a health monitor (TC_Data_Source_Health_Monitor) that records check results and can alert you before visitors notice. Each check returns a status of healthy, degraded (reachable but missing expected keys), or failed, and history is retained for 7 days.

Quick diagnostic checklist

  1. Reproduce while logged in as an admin to read the real error in the .tc-admin-error-helper panel.
  2. Open the exact source URL in a new tab — does it return raw JSON/CSV with HTTP 200?
  3. If "blocked for safety," the URL is a private/local address — use the public hostname or a local file path.
  4. Open the browser console for client-side failures: TableCrafter: Load failed plus a CORS or network error points to the upstream host.
  5. For "Path Error" or blank columns, fix the root attribute to point at the array of row objects.
  6. Run wp tablecrafter clear-cache after any change, then reload.

Once your source loads cleanly, continue with data-sources.html to learn every supported source type, or refine column selection and labels in columns.html.