Common Errors
This document provides solutions for the most frequently encountered Fluree errors.
LEDGER_NOT_FOUND
{
"error": "NotFound",
"message": "Ledger not found: mydb:main",
"code": "LEDGER_NOT_FOUND"
}
Causes
- Ledger doesn’t exist
- Typo in ledger name
- Wrong branch name
- Nameservice not initialized
Solutions
Check ledger exists:
curl http://localhost:8090/v1/fluree/ledgers
Create ledger:
curl -X POST "http://localhost:8090/v1/fluree/create" \
-H "Content-Type: application/json" \
-d '{"ledger": "mydb:main"}'
Verify spelling:
- Check for typos in ledger name
- Verify branch name (default is
main) - Check case sensitivity
PARSE_ERROR
{
"error": "ParseError",
"message": "Invalid JSON-LD: unexpected token at line 5",
"code": "PARSE_ERROR",
"details": {
"line": 5,
"column": 12
}
}
Causes
- Invalid JSON syntax
- Invalid JSON-LD structure
- Invalid SPARQL syntax
- Missing required fields
Solutions
Validate JSON:
# Use jq to validate
cat query.json | jq .
Check JSON-LD:
- Validate @context format
- Check @id and @type values
- Verify array vs object usage
Check SPARQL:
- Validate syntax online
- Check PREFIX declarations
- Verify quote matching
Common JSON Mistakes:
// Bad: trailing comma
{
"select": ["?name"],
"where": [...],
}
// Good: no trailing comma
{
"select": ["?name"],
"where": [...]
}
INVALID_IRI
{
"error": "ValidationError",
"message": "Invalid IRI: not a valid URI",
"code": "INVALID_IRI",
"details": {
"iri": "not a uri"
}
}
Causes
- Malformed IRI
- Missing namespace prefix
- Invalid characters
- Spaces in IRI
Solutions
Use valid IRIs:
// Good
{"@id": "http://example.org/alice"}
{"@id": "ex:alice"}
// Bad
{"@id": "not a uri"}
{"@id": "alice"} // Missing namespace
{"@id": "ex:alice smith"} // Space
Define namespace:
{
"@context": {
"ex": "http://example.org/ns/"
},
"@graph": [
{"@id": "ex:alice"} // Now valid
]
}
URL encode spaces:
{"@id": "ex:alice%20smith"}
UNRESOLVED_COMPACT_IRI
Unresolved compact IRI 'ex:Person': prefix 'ex' is not defined in @context.
If this is intended as an absolute IRI, use a full form (e.g. http://...)
or add the prefix to @context.
This error fires from the JSON-LD strict compact-IRI guard. A value that looks like a compact IRI (prefix:suffix) appeared in an IRI position, but prefix is not defined in @context and is not a recognised absolute scheme.
Causes
- Forgotten
@contexton a query or transaction - Misspelled or missing prefix in
@context - Intentionally using a bare
prefix:suffixstring as an opaque identifier
Solutions
Add the missing prefix to @context (most common fix):
{
"@context": {"ex": "http://example.org/ns/"},
"@graph": [{"@id": "ex:alice", "ex:name": "Alice"}]
}
Use a full absolute IRI instead of the compact form:
{
"@graph": [
{"@id": "http://example.org/ns/alice", "http://example.org/ns/name": "Alice"}
]
}
Opt out of the guard for legacy data where bare prefix:suffix strings are intentional:
{
"@context": {"ex": "http://example.org/ns/"},
"opts": {"strictCompactIri": false},
"@graph": [{"@id": "legacy:alice", "ex:name": "Alice"}]
}
The opt-out applies to both queries and transactions. See IRIs and @context — Strict Compact-IRI Guard for the full policy.
QUERY_TIMEOUT
{
"error": "Timeout",
"message": "Query execution exceeded timeout of 30000ms",
"code": "QUERY_TIMEOUT",
"details": {
"timeout_ms": 30000,
"elapsed_ms": 31245
}
}
Causes
- Complex query
- Large result set
- High indexing lag
- Insufficient resources
Solutions
Add LIMIT:
{
"select": ["?name"],
"where": [...],
"limit": 100 // Add limit
}
Add filters:
{
"where": [...],
"filter": "?age > 18" // Reduce result set
}
Check indexing lag:
curl http://localhost:8090/v1/fluree/info/mydb:main
# If (t - index.t) is large, wait for indexing (or reduce write rate)
Simplify query:
- Break into smaller queries
- Remove unnecessary joins
- Use more specific patterns
Increase timeout: the limit is server-wide (default 15 minutes; 0 disables it), not per
request:
FLUREE_QUERY_TIMEOUT_MS=1800000 fluree server run
POLICY_DENIED
{
"error": "Forbidden",
"message": "Policy denies access to ledger mydb:main",
"code": "POLICY_DENIED",
"details": {
"subject": "did:key:z6Mkh...",
"action": "query",
"ledger": "mydb:main"
}
}
Causes
- No permission for operation
- Missing authentication
- Policy misconfiguration
- Wrong DID/identity
Solutions
Check authentication:
# Are you sending credentials?
curl -H "Authorization: Bearer token" ...
Verify policy:
# Query policies
SELECT ?policy ?subject ?action ?allow
WHERE {
?policy a f:Policy .
?policy f:subject ?subject .
?policy f:action ?action .
?policy f:allow ?allow .
}
Check whether policy filtered the request:
curl -X POST http://localhost:8090/v1/fluree/query/mydb \
-H "fluree-track-policy: true" \
-H "Authorization: Bearer <token>" \
-d '{...}'
The response reports which policies ran (policy) and whether policy governed
the request at all (policy_enforcement). See
Detecting that policy was applied.
Check DID:
- Verify DID in signed request
- Check DID is registered
- Verify public key
TYPE_ERROR
{
"error": "TypeError",
"message": "Expected integer, got string",
"code": "TYPE_ERROR",
"details": {
"expected": "xsd:integer",
"actual": "xsd:string",
"value": "not a number"
}
}
Causes
- Wrong datatype
- Type mismatch in comparison
- Invalid type conversion
Solutions
Use correct types:
// Good
{"ex:age": 30}
{"ex:age": {"@value": "30", "@type": "xsd:integer"}}
// Bad
{"ex:age": "30"} // String, not integer
Check type constraints:
- Verify expected types
- Use explicit @type
- Validate before submitting
PAYLOAD_TOO_LARGE
A 413 carries one of two @type codes — branch on @type, not the status
(see API Errors for the full contract):
{
"error": "request body exceeds the configured limit",
"status": 413,
"@type": "err:db/PayloadTooLarge"
}
{
"error": "Transaction would exceed novelty limit: current=0, delta=2048576, max=1048576",
"status": 413,
"@type": "err:db/NoveltyDeltaTooLarge"
}
Causes
err:db/PayloadTooLarge: the raw HTTP request body exceeds the server’s configured body-size limit (refused before parsing)err:db/NoveltyDeltaTooLarge: the parsed transaction’s novelty delta alone meets or exceedsreindex_max_bytes— no indexer draining can ever admit it, so retrying the same request can never succeed
Solutions
Batch large transactions:
const batchSize = 1000;
for (let i = 0; i < entities.length; i += batchSize) {
const batch = entities.slice(i, i + batchSize);
await transact({"@graph": batch});
}
Use LIMIT for queries:
{
"select": ["?name"],
"where": [...],
"limit": 1000 // Paginate
}
Increase limits (if appropriate):
# Raise the request body limit (err:db/PayloadTooLarge); default 50 MB
fluree server run -- --body-limit 104857600
# Raise the novelty hard limit (err:db/NoveltyDeltaTooLarge)
fluree server run -- --reindex-max-bytes 2147483648
DATATYPE_LIMIT_EXCEEDED
{
"error": "datatype limit exceeded: the ledger holds 16369 of at most 16369 non-reserved datatypes, and this write would add 1 more",
"status": 422,
"@type": "err:db/DatatypeLimitExceeded"
}
Causes
The write uses datatypes the ledger has not seen before, and the ledger has no room for them. A ledger holds at most 16,369 distinct datatypes beyond 15 reserved ones. Every datatype counts from its first use, even after its data is retracted. See Datatype Limit for which datatypes count.
The write was refused before anything was committed, so the ledger is unchanged. Retrying the same write cannot succeed.
Solutions
Reuse datatypes the ledger already holds. Values typed with an existing datatype are always accepted.
Move the varying part out of the datatype. Unit and currency vocabularies often use one datatype per unit. Record the unit in its own property instead:
ex:room1 ex:area "42.5"^^xsd:decimal ;
ex:areaUnit unit:SquareMetre .
STORAGE_ERROR
{
"error": "StorageError",
"message": "Cannot write to storage",
"code": "STORAGE_ERROR"
}
Causes
- Disk full (file storage)
- Permission errors
- AWS connectivity (AWS storage)
- Storage backend down
Solutions
File Storage:
# Check disk space
df -h /var/lib/fluree
# Check permissions
ls -la /var/lib/fluree
sudo chown -R fluree:fluree /var/lib/fluree
AWS Storage:
# Check AWS credentials
aws sts get-caller-identity
# Check S3 access
aws s3 ls s3://fluree-prod-data/
# Check DynamoDB
aws dynamodb describe-table --table-name fluree-nameservice
HIGH_INDEXING_LAG
Not an error, but a warning condition.
Symptoms
curl http://localhost:8090/v1/fluree/info/mydb:main
{
"commit_t": 150,
"index_t": 0
}
Causes
- Transaction rate exceeds indexing capacity
- Large transactions
- Insufficient resources
- Storage bottleneck
Solutions
Tune indexing:
fluree server run -- \
--indexing-enabled \
--reindex-min-bytes 100000 \
--reindex-max-bytes 1000000
Reduce transaction rate:
// Add delay between transactions
await transact(data);
await sleep(100);
Wait for catchup:
async function waitForIndexing() {
while (true) {
const status = await getStatus();
const lag = status.commit_t - status.index_t;
if (lag < 10) break;
await sleep(1000);
}
}
Add resources:
- More CPU
- More memory
- Faster disk
CONCURRENT_MODIFICATION
{
"error": "Conflict",
"message": "Concurrent modification detected",
"code": "CONCURRENT_MODIFICATION"
}
Causes
- Multiple processes updating same entity
- Nameservice contention
- Race condition
Solutions
Implement retry:
async function transactWithRetry(data, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await transact(data);
} catch (err) {
if (err.code === 'CONCURRENT_MODIFICATION' && i < maxRetries - 1) {
await sleep(Math.pow(2, i) * 100);
continue;
}
throw err;
}
}
}
Use upsert for retry-friendly transactions:
# Upsert is more retry-friendly for idempotent entity transactions
POST /upsert?ledger=mydb:main
SIGNATURE_VERIFICATION_FAILED
{
"error": "SignatureVerificationFailed",
"message": "Invalid signature",
"code": "INVALID_SIGNATURE"
}
Causes
- Wrong private key
- Payload modified after signing
- Incorrect algorithm
- Key not registered
Solutions
Verify signing process:
// Ensure payload not modified
const payload = JSON.stringify(transaction);
const jws = await sign(payload, privateKey);
// Don't modify payload after signing
Check algorithm:
{
"alg": "EdDSA", // Must match key type
"kid": "did:key:z6Mkh..."
}
Verify public-key material: standalone server signed requests use the key
material embedded in supported JWS/JWT headers (or configured OIDC JWKS). There
is no /admin/keys registration endpoint.
Memory Issues
Symptoms
- Out of memory errors
- Server crashes
- Slow performance
- Swap usage
Solutions
Check memory:
curl http://localhost:8090/v1/fluree/stats
Reduce memory usage:
# See docs/operations/configuration.md for current memory-related flags.
# In general: reduce write/query load, reduce indexing lag, and provision more RAM.
Add more RAM:
- Upgrade server
- Use cloud instance with more memory
Reduce novelty:
- Index more frequently
- Reduce transaction size
Troubleshooting Checklist
When encountering issues, check:
- Server is running
- Can connect to server
- Health endpoint returns healthy
- Logs show no errors
- Ledger exists
- Correct ledger name/branch
- Valid JSON-LD/SPARQL syntax
- Sufficient resources (disk, memory)
- No network issues
- Authentication working (if required)
Related Documentation
- Debugging Queries - Query-specific debugging
- API Errors - HTTP error reference
- Operations - Operational guides
- Telemetry - Monitoring and logging