> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blnkfinance.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 0.15.1 Migration Guide

> Migration guide for the transaction lock duration overflow fixed in Blnk v0.15.1.

export const RelatedTopics = ({title = "Related topics", items = []}) => {
  if (!items.length) {
    return null;
  }
  return <nav className="related-topics not-prose mt-20 mb-10 flex flex-col" aria-label={title}>
      <p className="related-topics-heading m-0 border-b border-zinc-200 pb-3 text-sm font-medium text-zinc-500 dark:border-white/10 dark:text-zinc-400">
        {title}
      </p>
      <ul className="related-topics-list m-0 mt-3 flex list-none flex-col gap-0.5 p-0">
        {items.map(item => {
    const isExternal = typeof item.href === "string" && (/^https?:\/\//i).test(item.href);
    return <li key={item.href} className="m-0 p-0">
              <a href={item.href} target={isExternal ? "_blank" : undefined} rel={isExternal ? "noopener noreferrer" : undefined} className="related-topics-link group inline-flex items-center gap-2 text-sm font-semibold text-zinc-700 no-underline transition-colors dark:text-zinc-300">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="related-topics-icon shrink-0 text-zinc-400 dark:text-zinc-500" aria-hidden="true">
                  <path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" />
                  <path d="M14 2v4a2 2 0 0 0 2 2h4" />
                  <path d="M10 9H8" />
                  <path d="M16 13H8" />
                  <path d="M16 17H8" />
                </svg>
                <span className="relative top-px transition-colors group-hover:text-[#DD7B1B]">
                  {item.title}
                </span>
              </a>
            </li>;
  })}
      </ul>
    </nav>;
};

export const CtaCallout = props => {
  const {title, buttonLabel, href, trackingEvent, buttonTarget, rel = "noopener noreferrer", children} = props;
  const handleCtaClick = () => {
    if (typeof window === "undefined" || !trackingEvent) {
      return;
    }
    try {
      window.dispatchEvent(new CustomEvent("blnk:docs-cta", {
        detail: {
          name: trackingEvent,
          href
        }
      }));
    } catch {}
    try {
      window.posthog?.capture?.(trackingEvent, {
        href
      });
    } catch {}
    const gaPayload = {
      cta_href: href
    };
    try {
      window.gtag?.("event", trackingEvent, gaPayload);
    } catch {}
    try {
      window.dataLayer = window.dataLayer || [];
      window.dataLayer.push({
        event: trackingEvent,
        ...gaPayload
      });
    } catch {}
  };
  const isExternal = typeof href === "string" && (/^https?:\/\//i).test(href);
  const target = buttonTarget ?? (isExternal ? "_blank" : undefined);
  const linkRel = isExternal ? rel : undefined;
  return <section className="cta-callout not-prose relative my-8 w-full min-w-0 overflow-hidden rounded-xl border border-zinc-200 p-5 dark:border-white/10">
      <div className="cta-callout-noise" aria-hidden="true" />
      <div className="cta-callout-layout">
        {title ? <div className="cta-callout-title-row">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 28" width="14" height="14" className="cta-callout-icon shrink-0 text-zinc-800 dark:text-zinc-200" aria-hidden="true">
              <g fill="none" fillRule="nonzero">
                <path d="M28 0v28H0V0h28ZM14.691833333333335 27.134333333333334l-0.012833333333333334 0.0023333333333333335 -0.08283333333333333 0.04083333333333334 -0.023333333333333334 0.004666666666666667 -0.016333333333333335 -0.004666666666666667 -0.08283333333333333 -0.04083333333333334c-0.011666666666666667 -0.004666666666666667 -0.022166666666666668 -0.0011666666666666668 -0.028000000000000004 0.005833333333333334l-0.004666666666666667 0.011666666666666667 -0.019833333333333335 0.49933333333333335 0.005833333333333334 0.023333333333333334 0.011666666666666667 0.015166666666666667 0.12133333333333333 0.08633333333333333 0.0175 0.004666666666666667 0.014000000000000002 -0.004666666666666667 0.12133333333333333 -0.08633333333333333 0.014000000000000002 -0.018666666666666668 0.004666666666666667 -0.019833333333333335 -0.019833333333333335 -0.4981666666666667c-0.0023333333333333335 -0.011666666666666667 -0.0105 -0.019833333333333335 -0.019833333333333335 -0.021Zm0.3091666666666667 -0.13183333333333336 -0.015166666666666667 0.0023333333333333335 -0.21583333333333335 0.1085 -0.011666666666666667 0.011666666666666667 -0.0035000000000000005 0.012833333333333334 0.021 0.5016666666666667 0.005833333333333334 0.014000000000000002 0.009333333333333334 0.008166666666666668 0.23450000000000004 0.1085c0.014000000000000002 0.004666666666666667 0.026833333333333334 0 0.03383333333333334 -0.009333333333333334l0.004666666666666667 -0.016333333333333335 -0.03966666666666667 -0.7163333333333334c-0.0035000000000000005 -0.014000000000000002 -0.011666666666666667 -0.023333333333333334 -0.023333333333333334 -0.025666666666666667Zm-0.8341666666666667 0.0023333333333333335a0.026833333333333334 0.026833333333334334 0 0 0 -0.0315 0.007000000000000001l-0.007000000000000001 0.016333333333333335 -0.03966666666666667 0.7163333333333334c0 0.014000000000000002 0.008166666666666668 0.023333333333333334 0.019833333333333335 0.028000000000000004l0.0175 -0.0023333333333333335 0.23450000000000004 -0.1085 0.011666666666666667 -0.009333333333333334 0.004666666666666667 -0.012833333333333334 0.019833333333333335 -0.5016666666666667 -0.0035000000000000005 -0.014000000000000002 -0.011666666666666667 -0.011666666666666667 -0.21466666666666667 -0.10733333333333334Z" strokeWidth="1.1667" />
                <path fill="currentColor" d="M14 2.916666666666667A1.75 1.75 0 0 1 15.750000000000002 4.666666666666667v6.302333333333334L21.207666666666668 7.816666666666667a1.75 1.75 0 0 1 1.75 3.031L17.5 14l5.457666666666667 3.151166666666667a1.75 1.75 0 0 1 -1.75 3.031l-5.457666666666667 -3.1500000000000004V23.333333333333336a1.75 1.75 0 0 1 -3.5 0v-6.302333333333334L6.792333333333334 20.183333333333337a1.75 1.75 0 1 1 -1.75 -3.031L10.5 14 5.042333333333334 10.848833333333333a1.75 1.75 0 0 1 1.75 -3.031l5.457666666666667 3.1500000000000004V4.666666666666667A1.75 1.75 0 0 1 14 2.916666666666667Z" strokeWidth="1.1667" />
              </g>
            </svg>
            <p className="cta-callout-title min-w-0 font-semibold text-zinc-800 dark:text-zinc-200">
              {title}
            </p>
          </div> : null}
        <div className={`cta-callout-body text-sm leading-normal text-zinc-800 dark:text-zinc-200${title ? " cta-callout-body--indented" : ""}`}>
          {children}
        </div>
        <a href={href} target={target} rel={linkRel} onClick={handleCtaClick} data-docs-cta={trackingEvent || undefined} className="cta-callout-button inline-flex items-center justify-center gap-1 rounded-full bg-white px-3 py-1.5 text-sm font-semibold transition hover:bg-zinc-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/50 dark:bg-white dark:hover:bg-zinc-200">
          {buttonLabel}
          <span className="cta-callout-button-arrow" aria-hidden="true">
            →
          </span>
        </a>
      </div>
    </section>;
};

This guide covers the `BLNK_TRANSACTION_LOCK_DURATION` overflow fixed in Blnk Core **0.15.1**.

If you run **0.10.3 through 0.15.0** and set this value manually (especially as a Go duration such as `1m`), upgrade before you rely on that config.

***

## Summary

|                       |                                                                                             |
| :-------------------- | :------------------------------------------------------------------------------------------ |
| **Affected versions** | 0.10.3 through 0.15.0                                                                       |
| **Fixed in**          | 0.15.1 and later                                                                            |
| **Symptom**           | Redis balance locks can live for about **147 years** after a crash or abandoned run         |
| **Action**            | Upgrade to **0.15.1+**, confirm your lock duration config, then clean up any orphaned locks |

***

## Who is affected?

You are affected if both are true:

1. You run Blnk Core **0.10.3 through 0.15.0**
2. You set `BLNK_TRANSACTION_LOCK_DURATION` (or `transaction.lock_duration`) yourself

You are most at risk if the env value uses Go duration format at or above one second, for example:

```bash theme={"system"}
BLNK_TRANSACTION_LOCK_DURATION=1m
BLNK_TRANSACTION_LOCK_DURATION=60s
BLNK_TRANSACTION_LOCK_DURATION=5m
```

If you never override lock duration, the built-in default is not subject to this overflow path. Still upgrade to stay on a fixed release.

***

## What happened?

On affected versions, Blnk could multiply an already-parsed duration by `time.Second` again during config load.

Example with `BLNK_TRANSACTION_LOCK_DURATION=1m`:

1. `1m` parses to 60 seconds in nanoseconds
2. Config load multiplies by `time.Second` again
3. The value overflows a signed `int64` into a positive duration of about **147 years**
4. Redis receives that value as the lock TTL (`SET NX`)

Locks are keyed by balance ID. If a process crashes before unlock, that balance can stay locked until the TTL expires or you delete the key.

0.15.1 only multiplies by `time.Second` when the loaded value is greater than zero and less than one second (so JSON integer seconds still work). Parsed Go durations such as `1m` are left unchanged.

***

## Migration steps

<Steps>
  <Step title="Upgrade to 0.15.1 or later">
    Upgrade Blnk Core to **0.15.1+** on every server and worker that shares your Redis instance. Do this before you set or keep a manual lock duration.

    See [Install](/home/install) or [Deploy](/home/deploy).
  </Step>

  <Step title="Confirm your lock duration config">
    After upgrade, Go duration env values apply as written:

    ```bash theme={"system"}
    BLNK_TRANSACTION_LOCK_DURATION=1m
    ```

    In `blnk.json`, `lock_duration` remains integer **seconds**:

    ```json theme={"system"}
    {
      "transaction": {
        "lock_duration": 60
      }
    }
    ```

    See [Lock settings](/advanced/configuration/transactions#lock-settings).
  </Step>

  <Step title="Clean up orphaned Redis locks">
    After upgrade, check balances that stay unavailable or keep failing with lock errors.

    Redis lock keys are the balance IDs themselves (for example `bln_…`). Inspect TTL, then delete only when you are sure no live transaction owns the lock:

    ```bash theme={"system"}
    redis-cli TTL bln_<balance_id>
    redis-cli DEL bln_<balance_id>
    ```

    A healthy lock TTL is on the order of your configured lock duration (seconds or minutes). A TTL on the order of years is a leftover from the overflow.

    <Warning>
      Only delete a key after you confirm no live server or worker still holds that lock. Deleting an active lock can allow concurrent writes to the same balance.
    </Warning>
  </Step>
</Steps>

***

## Temporary workaround (not recommended)

If you cannot upgrade yet and must set the duration on **0.10.3 through 0.15.0**, a value below one second is multiplied into seconds by the buggy path. For example, `60ms` becomes 60 seconds after the extra multiply.

```bash theme={"system"}
BLNK_TRANSACTION_LOCK_DURATION=60ms
```

<Warning>
  Remove this workaround when you upgrade to 0.15.1+. On fixed versions, `60ms` is a 60-millisecond lock, which is far too short for production.
</Warning>

Prefer upgrading over relying on this behavior.

***

## Migration checklist

* Upgrade every Core server and worker to **0.15.1 or later**
* Keep or set `BLNK_TRANSACTION_LOCK_DURATION` with a real Go duration (for example `1m`) only after upgrade
* Remove any sub-second workaround values such as `60ms`
* Find stuck balances and inspect Redis `TTL` on their balance ID keys
* Delete orphaned locks only after confirming no live owner
* Re-test a transaction against each cleaned balance

***

<Note>
  This migration guide covers the lock duration overflow fixed in Blnk v0.15.1. For other fixes in that release, see the [release notes](/changelog/blnk-core).
</Note>

***

## Need help?

We are very happy to help you make the most of Blnk, regardless of whether it is your first time or you are switching from another tool.

To ask questions or discuss issues, please [contact us](mailto:support@blnkfinance.com) or [join our Discord community](https://discord.gg/7WNv94zPpx).

<CtaCallout title="Connect your ledger to Blnk Cloud" href="https://cloud.blnkfinance.com/auth/sign-up?utm_source=blnk_docs&utm_medium=documentation&utm_campaign=need-help" buttonLabel="Open Blnk Cloud" trackingEvent="clicked_cloud_signup">
  Sign up and manage your ledger with our back-office dashboard. You can invite teammates to collaborate and manage your ledger operations directly from the dashboard.
</CtaCallout>

<RelatedTopics
  items={[
{ title: "Lock settings", href: "/advanced/configuration/transactions#lock-settings" },
{ title: "Handling concurrency", href: "/guides/concurrency" },
{ title: "0.15.0 migration", href: "/changelog/v15-migration" },
{ title: "Install", href: "/home/install" },
]}
/>
